4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
678 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
679 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
682 "Roo.bootstrap.dash");
685 * Ext JS Library 1.1.1
686 * Copyright(c) 2006-2007, Ext JS, LLC.
688 * Originally Released Under LGPL - original licence link has changed is not relivant.
691 * <script type="text/javascript">
695 // wrappedn so fnCleanup is not in global scope...
697 function fnCleanUp() {
698 var p = Function.prototype;
699 delete p.createSequence;
701 delete p.createDelegate;
702 delete p.createCallback;
703 delete p.createInterceptor;
705 window.detachEvent("onunload", fnCleanUp);
707 window.attachEvent("onunload", fnCleanUp);
714 * These functions are available on every Function object (any JavaScript function).
716 Roo.apply(Function.prototype, {
718 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
719 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
720 * Will create a function that is bound to those 2 args.
721 * @return {Function} The new function
723 createCallback : function(/*args...*/){
724 // make args available, in function below
725 var args = arguments;
728 return method.apply(window, args);
733 * Creates a delegate (callback) that sets the scope to obj.
734 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
735 * Will create a function that is automatically scoped to this.
736 * @param {Object} obj (optional) The object for which the scope is set
737 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
738 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
739 * if a number the args are inserted at the specified position
740 * @return {Function} The new function
742 createDelegate : function(obj, args, appendArgs){
745 var callArgs = args || arguments;
746 if(appendArgs === true){
747 callArgs = Array.prototype.slice.call(arguments, 0);
748 callArgs = callArgs.concat(args);
749 }else if(typeof appendArgs == "number"){
750 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
751 var applyArgs = [appendArgs, 0].concat(args); // create method call params
752 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
754 return method.apply(obj || window, callArgs);
759 * Calls this function after the number of millseconds specified.
760 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
761 * @param {Object} obj (optional) The object for which the scope is set
762 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764 * if a number the args are inserted at the specified position
765 * @return {Number} The timeout id that can be used with clearTimeout
767 defer : function(millis, obj, args, appendArgs){
768 var fn = this.createDelegate(obj, args, appendArgs);
770 return setTimeout(fn, millis);
776 * Create a combined function call sequence of the original function + the passed function.
777 * The resulting function returns the results of the original function.
778 * The passed fcn is called with the parameters of the original function
779 * @param {Function} fcn The function to sequence
780 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
781 * @return {Function} The new function
783 createSequence : function(fcn, scope){
784 if(typeof fcn != "function"){
789 var retval = method.apply(this || window, arguments);
790 fcn.apply(scope || this || window, arguments);
796 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
797 * The resulting function returns the results of the original function.
798 * The passed fcn is called with the parameters of the original function.
800 * @param {Function} fcn The function to call before the original
801 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
802 * @return {Function} The new function
804 createInterceptor : function(fcn, scope){
805 if(typeof fcn != "function"){
812 if(fcn.apply(scope || this || window, arguments) === false){
815 return method.apply(this || window, arguments);
821 * Ext JS Library 1.1.1
822 * Copyright(c) 2006-2007, Ext JS, LLC.
824 * Originally Released Under LGPL - original licence link has changed is not relivant.
827 * <script type="text/javascript">
830 Roo.applyIf(String, {
835 * Escapes the passed string for ' and \
836 * @param {String} string The string to escape
837 * @return {String} The escaped string
840 escape : function(string) {
841 return string.replace(/('|\\)/g, "\\$1");
845 * Pads the left side of a string with a specified character. This is especially useful
846 * for normalizing number and date strings. Example usage:
848 var s = String.leftPad('123', 5, '0');
849 // s now contains the string: '00123'
851 * @param {String} string The original string
852 * @param {Number} size The total length of the output string
853 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
854 * @return {String} The padded string
857 leftPad : function (val, size, ch) {
858 var result = new String(val);
859 if(ch === null || ch === undefined || ch === '') {
862 while (result.length < size) {
863 result = ch + result;
869 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
870 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
872 var cls = 'my-class', text = 'Some text';
873 var s = String.format('<div class="{0}">{1}</div>', cls, text);
874 // s now contains the string: '<div class="my-class">Some text</div>'
876 * @param {String} string The tokenized string to be formatted
877 * @param {String} value1 The value to replace token {0}
878 * @param {String} value2 Etc...
879 * @return {String} The formatted string
882 format : function(format){
883 var args = Array.prototype.slice.call(arguments, 1);
884 return format.replace(/\{(\d+)\}/g, function(m, i){
885 return Roo.util.Format.htmlEncode(args[i]);
893 * Utility function that allows you to easily switch a string between two alternating values. The passed value
894 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
895 * they are already different, the first value passed in is returned. Note that this method returns the new value
896 * but does not change the current string.
898 // alternate sort directions
899 sort = sort.toggle('ASC', 'DESC');
901 // instead of conditional logic:
902 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
904 * @param {String} value The value to compare to the current string
905 * @param {String} other The new value to use if the string already equals the first value passed in
906 * @return {String} The new value
909 String.prototype.toggle = function(value, other){
910 return this == value ? other : value;
915 * Remove invalid unicode characters from a string
917 * @return {String} The clean string
919 String.prototype.unicodeClean = function () {
920 return this.replace(/[\s\S]/g,
921 function(character) {
922 if (character.charCodeAt()< 256) {
926 encodeURIComponent(character);
937 * Ext JS Library 1.1.1
938 * Copyright(c) 2006-2007, Ext JS, LLC.
940 * Originally Released Under LGPL - original licence link has changed is not relivant.
943 * <script type="text/javascript">
949 Roo.applyIf(Number.prototype, {
951 * Checks whether or not the current number is within a desired range. If the number is already within the
952 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
953 * exceeded. Note that this method returns the constrained value but does not change the current number.
954 * @param {Number} min The minimum number in the range
955 * @param {Number} max The maximum number in the range
956 * @return {Number} The constrained value if outside the range, otherwise the current value
958 constrain : function(min, max){
959 return Math.min(Math.max(this, min), max);
963 * Ext JS Library 1.1.1
964 * Copyright(c) 2006-2007, Ext JS, LLC.
966 * Originally Released Under LGPL - original licence link has changed is not relivant.
969 * <script type="text/javascript">
974 Roo.applyIf(Array.prototype, {
977 * Checks whether or not the specified object exists in the array.
978 * @param {Object} o The object to check for
979 * @return {Number} The index of o in the array (or -1 if it is not found)
981 indexOf : function(o){
982 for (var i = 0, len = this.length; i < len; i++){
983 if(this[i] == o) { return i; }
989 * Removes the specified object from the array. If the object is not found nothing happens.
990 * @param {Object} o The object to remove
992 remove : function(o){
993 var index = this.indexOf(o);
995 this.splice(index, 1);
999 * Map (JS 1.6 compatibility)
1000 * @param {Function} function to call
1002 map : function(fun )
1004 var len = this.length >>> 0;
1005 if (typeof fun != "function") {
1006 throw new TypeError();
1008 var res = new Array(len);
1009 var thisp = arguments[1];
1010 for (var i = 0; i < len; i++)
1013 res[i] = fun.call(thisp, this[i], i, this);
1021 * @param {Array} o The array to compare to
1022 * @returns {Boolean} true if the same
1024 equals : function(b)
1026 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1033 if (this.length !== b.length) {
1037 // sort?? a.sort().equals(b.sort());
1039 for (var i = 0; i < this.length; ++i) {
1040 if (this[i] !== b[i]) {
1052 * Ext JS Library 1.1.1
1053 * Copyright(c) 2006-2007, Ext JS, LLC.
1055 * Originally Released Under LGPL - original licence link has changed is not relivant.
1058 * <script type="text/javascript">
1064 * The date parsing and format syntax is a subset of
1065 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1066 * supported will provide results equivalent to their PHP versions.
1068 * Following is the list of all currently supported formats:
1071 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1073 Format Output Description
1074 ------ ---------- --------------------------------------------------------------
1075 d 10 Day of the month, 2 digits with leading zeros
1076 D Wed A textual representation of a day, three letters
1077 j 10 Day of the month without leading zeros
1078 l Wednesday A full textual representation of the day of the week
1079 S th English ordinal day of month suffix, 2 chars (use with j)
1080 w 3 Numeric representation of the day of the week
1081 z 9 The julian date, or day of the year (0-365)
1082 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1083 F January A full textual representation of the month
1084 m 01 Numeric representation of a month, with leading zeros
1085 M Jan Month name abbreviation, three letters
1086 n 1 Numeric representation of a month, without leading zeros
1087 t 31 Number of days in the given month
1088 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1089 Y 2007 A full numeric representation of a year, 4 digits
1090 y 07 A two digit representation of a year
1091 a pm Lowercase Ante meridiem and Post meridiem
1092 A PM Uppercase Ante meridiem and Post meridiem
1093 g 3 12-hour format of an hour without leading zeros
1094 G 15 24-hour format of an hour without leading zeros
1095 h 03 12-hour format of an hour with leading zeros
1096 H 15 24-hour format of an hour with leading zeros
1097 i 05 Minutes with leading zeros
1098 s 01 Seconds, with leading zeros
1099 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1100 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1101 T CST Timezone setting of the machine running the code
1102 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1105 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1107 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1108 document.write(dt.format('Y-m-d')); //2007-01-10
1109 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1110 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1113 * Here are some standard date/time patterns that you might find helpful. They
1114 * are not part of the source of Date.js, but to use them you can simply copy this
1115 * block of code into any script that is included after Date.js and they will also become
1116 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1119 ISO8601Long:"Y-m-d H:i:s",
1120 ISO8601Short:"Y-m-d",
1122 LongDate: "l, F d, Y",
1123 FullDateTime: "l, F d, Y g:i:s A",
1126 LongTime: "g:i:s A",
1127 SortableDateTime: "Y-m-d\\TH:i:s",
1128 UniversalSortableDateTime: "Y-m-d H:i:sO",
1135 var dt = new Date();
1136 document.write(dt.format(Date.patterns.ShortDate));
1141 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1142 * They generate precompiled functions from date formats instead of parsing and
1143 * processing the pattern every time you format a date. These functions are available
1144 * on every Date object (any javascript function).
1146 * The original article and download are here:
1147 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1154 Returns the number of milliseconds between this date and date
1155 @param {Date} date (optional) Defaults to now
1156 @return {Number} The diff in milliseconds
1157 @member Date getElapsed
1159 Date.prototype.getElapsed = function(date) {
1160 return Math.abs((date || new Date()).getTime()-this.getTime());
1162 // was in date file..
1166 Date.parseFunctions = {count:0};
1168 Date.parseRegexes = [];
1170 Date.formatFunctions = {count:0};
1173 Date.prototype.dateFormat = function(format) {
1174 if (Date.formatFunctions[format] == null) {
1175 Date.createNewFormat(format);
1177 var func = Date.formatFunctions[format];
1178 return this[func]();
1183 * Formats a date given the supplied format string
1184 * @param {String} format The format string
1185 * @return {String} The formatted date
1188 Date.prototype.format = Date.prototype.dateFormat;
1191 Date.createNewFormat = function(format) {
1192 var funcName = "format" + Date.formatFunctions.count++;
1193 Date.formatFunctions[format] = funcName;
1194 var code = "Date.prototype." + funcName + " = function(){return ";
1195 var special = false;
1197 for (var i = 0; i < format.length; ++i) {
1198 ch = format.charAt(i);
1199 if (!special && ch == "\\") {
1204 code += "'" + String.escape(ch) + "' + ";
1207 code += Date.getFormatCode(ch);
1210 /** eval:var:zzzzzzzzzzzzz */
1211 eval(code.substring(0, code.length - 3) + ";}");
1215 Date.getFormatCode = function(character) {
1216 switch (character) {
1218 return "String.leftPad(this.getDate(), 2, '0') + ";
1220 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1222 return "this.getDate() + ";
1224 return "Date.dayNames[this.getDay()] + ";
1226 return "this.getSuffix() + ";
1228 return "this.getDay() + ";
1230 return "this.getDayOfYear() + ";
1232 return "this.getWeekOfYear() + ";
1234 return "Date.monthNames[this.getMonth()] + ";
1236 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1238 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1240 return "(this.getMonth() + 1) + ";
1242 return "this.getDaysInMonth() + ";
1244 return "(this.isLeapYear() ? 1 : 0) + ";
1246 return "this.getFullYear() + ";
1248 return "('' + this.getFullYear()).substring(2, 4) + ";
1250 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1252 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1254 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1256 return "this.getHours() + ";
1258 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1260 return "String.leftPad(this.getHours(), 2, '0') + ";
1262 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1264 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1266 return "this.getGMTOffset() + ";
1268 return "this.getGMTColonOffset() + ";
1270 return "this.getTimezone() + ";
1272 return "(this.getTimezoneOffset() * -60) + ";
1274 return "'" + String.escape(character) + "' + ";
1279 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1280 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1281 * the date format that is not specified will default to the current date value for that part. Time parts can also
1282 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1283 * string or the parse operation will fail.
1286 //dt = Fri May 25 2007 (current date)
1287 var dt = new Date();
1289 //dt = Thu May 25 2006 (today's month/day in 2006)
1290 dt = Date.parseDate("2006", "Y");
1292 //dt = Sun Jan 15 2006 (all date parts specified)
1293 dt = Date.parseDate("2006-1-15", "Y-m-d");
1295 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1296 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1298 * @param {String} input The unparsed date as a string
1299 * @param {String} format The format the date is in
1300 * @return {Date} The parsed date
1303 Date.parseDate = function(input, format) {
1304 if (Date.parseFunctions[format] == null) {
1305 Date.createParser(format);
1307 var func = Date.parseFunctions[format];
1308 return Date[func](input);
1314 Date.createParser = function(format) {
1315 var funcName = "parse" + Date.parseFunctions.count++;
1316 var regexNum = Date.parseRegexes.length;
1317 var currentGroup = 1;
1318 Date.parseFunctions[format] = funcName;
1320 var code = "Date." + funcName + " = function(input){\n"
1321 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1322 + "var d = new Date();\n"
1323 + "y = d.getFullYear();\n"
1324 + "m = d.getMonth();\n"
1325 + "d = d.getDate();\n"
1326 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1327 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1328 + "if (results && results.length > 0) {";
1331 var special = false;
1333 for (var i = 0; i < format.length; ++i) {
1334 ch = format.charAt(i);
1335 if (!special && ch == "\\") {
1340 regex += String.escape(ch);
1343 var obj = Date.formatCodeToRegex(ch, currentGroup);
1344 currentGroup += obj.g;
1346 if (obj.g && obj.c) {
1352 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1353 + "{v = new Date(y, m, d, h, i, s);}\n"
1354 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1355 + "{v = new Date(y, m, d, h, i);}\n"
1356 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1357 + "{v = new Date(y, m, d, h);}\n"
1358 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1359 + "{v = new Date(y, m, d);}\n"
1360 + "else if (y >= 0 && m >= 0)\n"
1361 + "{v = new Date(y, m);}\n"
1362 + "else if (y >= 0)\n"
1363 + "{v = new Date(y);}\n"
1364 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1365 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1366 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1369 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1370 /** eval:var:zzzzzzzzzzzzz */
1375 Date.formatCodeToRegex = function(character, currentGroup) {
1376 switch (character) {
1380 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1383 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1384 s:"(\\d{1,2})"}; // day of month without leading zeroes
1387 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1388 s:"(\\d{2})"}; // day of month with leading zeroes
1392 s:"(?:" + Date.dayNames.join("|") + ")"};
1396 s:"(?:st|nd|rd|th)"};
1411 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1412 s:"(" + Date.monthNames.join("|") + ")"};
1415 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1416 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1419 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1420 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1423 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1424 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1435 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1439 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1440 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1444 c:"if (results[" + currentGroup + "] == 'am') {\n"
1445 + "if (h == 12) { h = 0; }\n"
1446 + "} else { if (h < 12) { h += 12; }}",
1450 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1451 + "if (h == 12) { h = 0; }\n"
1452 + "} else { if (h < 12) { h += 12; }}",
1457 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1458 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1462 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1463 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1466 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1470 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1475 "o = results[", currentGroup, "];\n",
1476 "var sn = o.substring(0,1);\n", // get + / - sign
1477 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1478 "var mn = o.substring(3,5) % 60;\n", // get minutes
1479 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1480 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1482 s:"([+\-]\\d{2,4})"};
1488 "o = results[", currentGroup, "];\n",
1489 "var sn = o.substring(0,1);\n",
1490 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1491 "var mn = o.substring(4,6) % 60;\n",
1492 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1493 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1499 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1502 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1503 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1504 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1508 s:String.escape(character)};
1513 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1514 * @return {String} The abbreviated timezone name (e.g. 'CST')
1516 Date.prototype.getTimezone = function() {
1517 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1521 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1522 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1524 Date.prototype.getGMTOffset = function() {
1525 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1526 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1527 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1531 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1532 * @return {String} 2-characters representing hours and 2-characters representing minutes
1533 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1535 Date.prototype.getGMTColonOffset = function() {
1536 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1537 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1539 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1543 * Get the numeric day number of the year, adjusted for leap year.
1544 * @return {Number} 0 through 364 (365 in leap years)
1546 Date.prototype.getDayOfYear = function() {
1548 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1549 for (var i = 0; i < this.getMonth(); ++i) {
1550 num += Date.daysInMonth[i];
1552 return num + this.getDate() - 1;
1556 * Get the string representation of the numeric week number of the year
1557 * (equivalent to the format specifier 'W').
1558 * @return {String} '00' through '52'
1560 Date.prototype.getWeekOfYear = function() {
1561 // Skip to Thursday of this week
1562 var now = this.getDayOfYear() + (4 - this.getDay());
1563 // Find the first Thursday of the year
1564 var jan1 = new Date(this.getFullYear(), 0, 1);
1565 var then = (7 - jan1.getDay() + 4);
1566 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1570 * Whether or not the current date is in a leap year.
1571 * @return {Boolean} True if the current date is in a leap year, else false
1573 Date.prototype.isLeapYear = function() {
1574 var year = this.getFullYear();
1575 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1579 * Get the first day of the current month, adjusted for leap year. The returned value
1580 * is the numeric day index within the week (0-6) which can be used in conjunction with
1581 * the {@link #monthNames} array to retrieve the textual day name.
1584 var dt = new Date('1/10/2007');
1585 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1587 * @return {Number} The day number (0-6)
1589 Date.prototype.getFirstDayOfMonth = function() {
1590 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1591 return (day < 0) ? (day + 7) : day;
1595 * Get the last day of the current month, adjusted for leap year. The returned value
1596 * is the numeric day index within the week (0-6) which can be used in conjunction with
1597 * the {@link #monthNames} array to retrieve the textual day name.
1600 var dt = new Date('1/10/2007');
1601 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1603 * @return {Number} The day number (0-6)
1605 Date.prototype.getLastDayOfMonth = function() {
1606 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1607 return (day < 0) ? (day + 7) : day;
1612 * Get the first date of this date's month
1615 Date.prototype.getFirstDateOfMonth = function() {
1616 return new Date(this.getFullYear(), this.getMonth(), 1);
1620 * Get the last date of this date's month
1623 Date.prototype.getLastDateOfMonth = function() {
1624 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1627 * Get the number of days in the current month, adjusted for leap year.
1628 * @return {Number} The number of days in the month
1630 Date.prototype.getDaysInMonth = function() {
1631 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1632 return Date.daysInMonth[this.getMonth()];
1636 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1637 * @return {String} 'st, 'nd', 'rd' or 'th'
1639 Date.prototype.getSuffix = function() {
1640 switch (this.getDate()) {
1657 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1660 * An array of textual month names.
1661 * Override these values for international dates, for example...
1662 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1681 * An array of textual day names.
1682 * Override these values for international dates, for example...
1683 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1699 Date.monthNumbers = {
1714 * Creates and returns a new Date instance with the exact same date value as the called instance.
1715 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1716 * variable will also be changed. When the intention is to create a new variable that will not
1717 * modify the original instance, you should create a clone.
1719 * Example of correctly cloning a date:
1722 var orig = new Date('10/1/2006');
1725 document.write(orig); //returns 'Thu Oct 05 2006'!
1728 var orig = new Date('10/1/2006');
1729 var copy = orig.clone();
1731 document.write(orig); //returns 'Thu Oct 01 2006'
1733 * @return {Date} The new Date instance
1735 Date.prototype.clone = function() {
1736 return new Date(this.getTime());
1740 * Clears any time information from this date
1741 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1742 @return {Date} this or the clone
1744 Date.prototype.clearTime = function(clone){
1746 return this.clone().clearTime();
1751 this.setMilliseconds(0);
1756 // safari setMonth is broken -- check that this is only donw once...
1757 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1758 Date.brokenSetMonth = Date.prototype.setMonth;
1759 Date.prototype.setMonth = function(num){
1761 var n = Math.ceil(-num);
1762 var back_year = Math.ceil(n/12);
1763 var month = (n % 12) ? 12 - n % 12 : 0 ;
1764 this.setFullYear(this.getFullYear() - back_year);
1765 return Date.brokenSetMonth.call(this, month);
1767 return Date.brokenSetMonth.apply(this, arguments);
1772 /** Date interval constant
1776 /** Date interval constant
1780 /** Date interval constant
1784 /** Date interval constant
1788 /** Date interval constant
1792 /** Date interval constant
1796 /** Date interval constant
1802 * Provides a convenient method of performing basic date arithmetic. This method
1803 * does not modify the Date instance being called - it creates and returns
1804 * a new Date instance containing the resulting date value.
1809 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1810 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1812 //Negative values will subtract correctly:
1813 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1814 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1816 //You can even chain several calls together in one line!
1817 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1818 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1821 * @param {String} interval A valid date interval enum value
1822 * @param {Number} value The amount to add to the current date
1823 * @return {Date} The new Date instance
1825 Date.prototype.add = function(interval, value){
1826 var d = this.clone();
1827 if (!interval || value === 0) { return d; }
1828 switch(interval.toLowerCase()){
1830 d.setMilliseconds(this.getMilliseconds() + value);
1833 d.setSeconds(this.getSeconds() + value);
1836 d.setMinutes(this.getMinutes() + value);
1839 d.setHours(this.getHours() + value);
1842 d.setDate(this.getDate() + value);
1845 var day = this.getDate();
1847 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1850 d.setMonth(this.getMonth() + value);
1853 d.setFullYear(this.getFullYear() + value);
1860 * Ext JS Library 1.1.1
1861 * Copyright(c) 2006-2007, Ext JS, LLC.
1863 * Originally Released Under LGPL - original licence link has changed is not relivant.
1866 * <script type="text/javascript">
1870 * @class Roo.lib.Dom
1873 * Dom utils (from YIU afaik)
1878 * Get the view width
1879 * @param {Boolean} full True will get the full document, otherwise it's the view width
1880 * @return {Number} The width
1883 getViewWidth : function(full) {
1884 return full ? this.getDocumentWidth() : this.getViewportWidth();
1887 * Get the view height
1888 * @param {Boolean} full True will get the full document, otherwise it's the view height
1889 * @return {Number} The height
1891 getViewHeight : function(full) {
1892 return full ? this.getDocumentHeight() : this.getViewportHeight();
1895 getDocumentHeight: function() {
1896 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1897 return Math.max(scrollHeight, this.getViewportHeight());
1900 getDocumentWidth: function() {
1901 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1902 return Math.max(scrollWidth, this.getViewportWidth());
1905 getViewportHeight: function() {
1906 var height = self.innerHeight;
1907 var mode = document.compatMode;
1909 if ((mode || Roo.isIE) && !Roo.isOpera) {
1910 height = (mode == "CSS1Compat") ?
1911 document.documentElement.clientHeight :
1912 document.body.clientHeight;
1918 getViewportWidth: function() {
1919 var width = self.innerWidth;
1920 var mode = document.compatMode;
1922 if (mode || Roo.isIE) {
1923 width = (mode == "CSS1Compat") ?
1924 document.documentElement.clientWidth :
1925 document.body.clientWidth;
1930 isAncestor : function(p, c) {
1937 if (p.contains && !Roo.isSafari) {
1938 return p.contains(c);
1939 } else if (p.compareDocumentPosition) {
1940 return !!(p.compareDocumentPosition(c) & 16);
1942 var parent = c.parentNode;
1947 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1950 parent = parent.parentNode;
1956 getRegion : function(el) {
1957 return Roo.lib.Region.getRegion(el);
1960 getY : function(el) {
1961 return this.getXY(el)[1];
1964 getX : function(el) {
1965 return this.getXY(el)[0];
1968 getXY : function(el) {
1969 var p, pe, b, scroll, bd = document.body;
1970 el = Roo.getDom(el);
1971 var fly = Roo.lib.AnimBase.fly;
1972 if (el.getBoundingClientRect) {
1973 b = el.getBoundingClientRect();
1974 scroll = fly(document).getScroll();
1975 return [b.left + scroll.left, b.top + scroll.top];
1981 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1988 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1995 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1996 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2003 if (p != el && pe.getStyle('overflow') != 'visible') {
2011 if (Roo.isSafari && hasAbsolute) {
2016 if (Roo.isGecko && !hasAbsolute) {
2018 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2019 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2023 while (p && p != bd) {
2024 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2036 setXY : function(el, xy) {
2037 el = Roo.fly(el, '_setXY');
2039 var pts = el.translatePoints(xy);
2040 if (xy[0] !== false) {
2041 el.dom.style.left = pts.left + "px";
2043 if (xy[1] !== false) {
2044 el.dom.style.top = pts.top + "px";
2048 setX : function(el, x) {
2049 this.setXY(el, [x, false]);
2052 setY : function(el, y) {
2053 this.setXY(el, [false, y]);
2057 * Portions of this file are based on pieces of Yahoo User Interface Library
2058 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2059 * YUI licensed under the BSD License:
2060 * http://developer.yahoo.net/yui/license.txt
2061 * <script type="text/javascript">
2065 Roo.lib.Event = function() {
2066 var loadComplete = false;
2068 var unloadListeners = [];
2070 var onAvailStack = [];
2072 var lastError = null;
2085 startInterval: function() {
2086 if (!this._interval) {
2088 var callback = function() {
2089 self._tryPreloadAttach();
2091 this._interval = setInterval(callback, this.POLL_INTERVAL);
2096 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2097 onAvailStack.push({ id: p_id,
2100 override: p_override,
2101 checkReady: false });
2103 retryCount = this.POLL_RETRYS;
2104 this.startInterval();
2108 addListener: function(el, eventName, fn) {
2109 el = Roo.getDom(el);
2114 if ("unload" == eventName) {
2115 unloadListeners[unloadListeners.length] =
2116 [el, eventName, fn];
2120 var wrappedFn = function(e) {
2121 return fn(Roo.lib.Event.getEvent(e));
2124 var li = [el, eventName, fn, wrappedFn];
2126 var index = listeners.length;
2127 listeners[index] = li;
2129 this.doAdd(el, eventName, wrappedFn, false);
2135 removeListener: function(el, eventName, fn) {
2138 el = Roo.getDom(el);
2141 return this.purgeElement(el, false, eventName);
2145 if ("unload" == eventName) {
2147 for (i = 0,len = unloadListeners.length; i < len; i++) {
2148 var li = unloadListeners[i];
2151 li[1] == eventName &&
2153 unloadListeners.splice(i, 1);
2161 var cacheItem = null;
2164 var index = arguments[3];
2166 if ("undefined" == typeof index) {
2167 index = this._getCacheIndex(el, eventName, fn);
2171 cacheItem = listeners[index];
2174 if (!el || !cacheItem) {
2178 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2180 delete listeners[index][this.WFN];
2181 delete listeners[index][this.FN];
2182 listeners.splice(index, 1);
2189 getTarget: function(ev, resolveTextNode) {
2190 ev = ev.browserEvent || ev;
2191 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2192 var t = ev.target || ev.srcElement;
2193 return this.resolveTextNode(t);
2197 resolveTextNode: function(node) {
2198 if (Roo.isSafari && node && 3 == node.nodeType) {
2199 return node.parentNode;
2206 getPageX: function(ev) {
2207 ev = ev.browserEvent || ev;
2208 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2210 if (!x && 0 !== x) {
2211 x = ev.clientX || 0;
2214 x += this.getScroll()[1];
2222 getPageY: function(ev) {
2223 ev = ev.browserEvent || ev;
2224 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2226 if (!y && 0 !== y) {
2227 y = ev.clientY || 0;
2230 y += this.getScroll()[0];
2239 getXY: function(ev) {
2240 ev = ev.browserEvent || ev;
2241 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2242 return [this.getPageX(ev), this.getPageY(ev)];
2246 getRelatedTarget: function(ev) {
2247 ev = ev.browserEvent || ev;
2248 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2249 var t = ev.relatedTarget;
2251 if (ev.type == "mouseout") {
2253 } else if (ev.type == "mouseover") {
2258 return this.resolveTextNode(t);
2262 getTime: function(ev) {
2263 ev = ev.browserEvent || ev;
2264 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2266 var t = new Date().getTime();
2270 this.lastError = ex;
2279 stopEvent: function(ev) {
2280 this.stopPropagation(ev);
2281 this.preventDefault(ev);
2285 stopPropagation: function(ev) {
2286 ev = ev.browserEvent || ev;
2287 if (ev.stopPropagation) {
2288 ev.stopPropagation();
2290 ev.cancelBubble = true;
2295 preventDefault: function(ev) {
2296 ev = ev.browserEvent || ev;
2297 if(ev.preventDefault) {
2298 ev.preventDefault();
2300 ev.returnValue = false;
2305 getEvent: function(e) {
2306 var ev = e || window.event;
2308 var c = this.getEvent.caller;
2310 ev = c.arguments[0];
2311 if (ev && Event == ev.constructor) {
2321 getCharCode: function(ev) {
2322 ev = ev.browserEvent || ev;
2323 return ev.charCode || ev.keyCode || 0;
2327 _getCacheIndex: function(el, eventName, fn) {
2328 for (var i = 0,len = listeners.length; i < len; ++i) {
2329 var li = listeners[i];
2331 li[this.FN] == fn &&
2332 li[this.EL] == el &&
2333 li[this.TYPE] == eventName) {
2345 getEl: function(id) {
2346 return document.getElementById(id);
2350 clearCache: function() {
2354 _load: function(e) {
2355 loadComplete = true;
2356 var EU = Roo.lib.Event;
2360 EU.doRemove(window, "load", EU._load);
2365 _tryPreloadAttach: function() {
2374 var tryAgain = !loadComplete;
2376 tryAgain = (retryCount > 0);
2381 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2382 var item = onAvailStack[i];
2384 var el = this.getEl(item.id);
2387 if (!item.checkReady ||
2390 (document && document.body)) {
2393 if (item.override) {
2394 if (item.override === true) {
2397 scope = item.override;
2400 item.fn.call(scope, item.obj);
2401 onAvailStack[i] = null;
2404 notAvail.push(item);
2409 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2413 this.startInterval();
2415 clearInterval(this._interval);
2416 this._interval = null;
2419 this.locked = false;
2426 purgeElement: function(el, recurse, eventName) {
2427 var elListeners = this.getListeners(el, eventName);
2429 for (var i = 0,len = elListeners.length; i < len; ++i) {
2430 var l = elListeners[i];
2431 this.removeListener(el, l.type, l.fn);
2435 if (recurse && el && el.childNodes) {
2436 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2437 this.purgeElement(el.childNodes[i], recurse, eventName);
2443 getListeners: function(el, eventName) {
2444 var results = [], searchLists;
2446 searchLists = [listeners, unloadListeners];
2447 } else if (eventName == "unload") {
2448 searchLists = [unloadListeners];
2450 searchLists = [listeners];
2453 for (var j = 0; j < searchLists.length; ++j) {
2454 var searchList = searchLists[j];
2455 if (searchList && searchList.length > 0) {
2456 for (var i = 0,len = searchList.length; i < len; ++i) {
2457 var l = searchList[i];
2458 if (l && l[this.EL] === el &&
2459 (!eventName || eventName === l[this.TYPE])) {
2464 adjust: l[this.ADJ_SCOPE],
2472 return (results.length) ? results : null;
2476 _unload: function(e) {
2478 var EU = Roo.lib.Event, i, j, l, len, index;
2480 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2481 l = unloadListeners[i];
2484 if (l[EU.ADJ_SCOPE]) {
2485 if (l[EU.ADJ_SCOPE] === true) {
2488 scope = l[EU.ADJ_SCOPE];
2491 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2492 unloadListeners[i] = null;
2498 unloadListeners = null;
2500 if (listeners && listeners.length > 0) {
2501 j = listeners.length;
2504 l = listeners[index];
2506 EU.removeListener(l[EU.EL], l[EU.TYPE],
2516 EU.doRemove(window, "unload", EU._unload);
2521 getScroll: function() {
2522 var dd = document.documentElement, db = document.body;
2523 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2524 return [dd.scrollTop, dd.scrollLeft];
2526 return [db.scrollTop, db.scrollLeft];
2533 doAdd: function () {
2534 if (window.addEventListener) {
2535 return function(el, eventName, fn, capture) {
2536 el.addEventListener(eventName, fn, (capture));
2538 } else if (window.attachEvent) {
2539 return function(el, eventName, fn, capture) {
2540 el.attachEvent("on" + eventName, fn);
2549 doRemove: function() {
2550 if (window.removeEventListener) {
2551 return function (el, eventName, fn, capture) {
2552 el.removeEventListener(eventName, fn, (capture));
2554 } else if (window.detachEvent) {
2555 return function (el, eventName, fn) {
2556 el.detachEvent("on" + eventName, fn);
2568 var E = Roo.lib.Event;
2569 E.on = E.addListener;
2570 E.un = E.removeListener;
2572 if (document && document.body) {
2575 E.doAdd(window, "load", E._load);
2577 E.doAdd(window, "unload", E._unload);
2578 E._tryPreloadAttach();
2582 * Portions of this file are based on pieces of Yahoo User Interface Library
2583 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2584 * YUI licensed under the BSD License:
2585 * http://developer.yahoo.net/yui/license.txt
2586 * <script type="text/javascript">
2592 * @class Roo.lib.Ajax
2599 request : function(method, uri, cb, data, options) {
2601 var hs = options.headers;
2604 if(hs.hasOwnProperty(h)){
2605 this.initHeader(h, hs[h], false);
2609 if(options.xmlData){
2610 this.initHeader('Content-Type', 'text/xml', false);
2612 data = options.xmlData;
2616 return this.asyncRequest(method, uri, cb, data);
2619 serializeForm : function(form) {
2620 if(typeof form == 'string') {
2621 form = (document.getElementById(form) || document.forms[form]);
2624 var el, name, val, disabled, data = '', hasSubmit = false;
2625 for (var i = 0; i < form.elements.length; i++) {
2626 el = form.elements[i];
2627 disabled = form.elements[i].disabled;
2628 name = form.elements[i].name;
2629 val = form.elements[i].value;
2631 if (!disabled && name){
2635 case 'select-multiple':
2636 for (var j = 0; j < el.options.length; j++) {
2637 if (el.options[j].selected) {
2639 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2642 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2650 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2663 if(hasSubmit == false) {
2664 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2669 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2674 data = data.substr(0, data.length - 1);
2682 useDefaultHeader:true,
2684 defaultPostHeader:'application/x-www-form-urlencoded',
2686 useDefaultXhrHeader:true,
2688 defaultXhrHeader:'XMLHttpRequest',
2690 hasDefaultHeaders:true,
2702 setProgId:function(id)
2704 this.activeX.unshift(id);
2707 setDefaultPostHeader:function(b)
2709 this.useDefaultHeader = b;
2712 setDefaultXhrHeader:function(b)
2714 this.useDefaultXhrHeader = b;
2717 setPollingInterval:function(i)
2719 if (typeof i == 'number' && isFinite(i)) {
2720 this.pollInterval = i;
2724 createXhrObject:function(transactionId)
2730 http = new XMLHttpRequest();
2732 obj = { conn:http, tId:transactionId };
2736 for (var i = 0; i < this.activeX.length; ++i) {
2740 http = new ActiveXObject(this.activeX[i]);
2742 obj = { conn:http, tId:transactionId };
2755 getConnectionObject:function()
2758 var tId = this.transactionId;
2762 o = this.createXhrObject(tId);
2764 this.transactionId++;
2775 asyncRequest:function(method, uri, callback, postData)
2777 var o = this.getConnectionObject();
2783 o.conn.open(method, uri, true);
2785 if (this.useDefaultXhrHeader) {
2786 if (!this.defaultHeaders['X-Requested-With']) {
2787 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2791 if(postData && this.useDefaultHeader){
2792 this.initHeader('Content-Type', this.defaultPostHeader);
2795 if (this.hasDefaultHeaders || this.hasHeaders) {
2799 this.handleReadyState(o, callback);
2800 o.conn.send(postData || null);
2806 handleReadyState:function(o, callback)
2810 if (callback && callback.timeout) {
2812 this.timeout[o.tId] = window.setTimeout(function() {
2813 oConn.abort(o, callback, true);
2814 }, callback.timeout);
2817 this.poll[o.tId] = window.setInterval(
2819 if (o.conn && o.conn.readyState == 4) {
2820 window.clearInterval(oConn.poll[o.tId]);
2821 delete oConn.poll[o.tId];
2823 if(callback && callback.timeout) {
2824 window.clearTimeout(oConn.timeout[o.tId]);
2825 delete oConn.timeout[o.tId];
2828 oConn.handleTransactionResponse(o, callback);
2831 , this.pollInterval);
2834 handleTransactionResponse:function(o, callback, isAbort)
2838 this.releaseObject(o);
2842 var httpStatus, responseObject;
2846 if (o.conn.status !== undefined && o.conn.status != 0) {
2847 httpStatus = o.conn.status;
2859 if (httpStatus >= 200 && httpStatus < 300) {
2860 responseObject = this.createResponseObject(o, callback.argument);
2861 if (callback.success) {
2862 if (!callback.scope) {
2863 callback.success(responseObject);
2868 callback.success.apply(callback.scope, [responseObject]);
2873 switch (httpStatus) {
2881 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2882 if (callback.failure) {
2883 if (!callback.scope) {
2884 callback.failure(responseObject);
2887 callback.failure.apply(callback.scope, [responseObject]);
2892 responseObject = this.createResponseObject(o, callback.argument);
2893 if (callback.failure) {
2894 if (!callback.scope) {
2895 callback.failure(responseObject);
2898 callback.failure.apply(callback.scope, [responseObject]);
2904 this.releaseObject(o);
2905 responseObject = null;
2908 createResponseObject:function(o, callbackArg)
2915 var headerStr = o.conn.getAllResponseHeaders();
2916 var header = headerStr.split('\n');
2917 for (var i = 0; i < header.length; i++) {
2918 var delimitPos = header[i].indexOf(':');
2919 if (delimitPos != -1) {
2920 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2928 obj.status = o.conn.status;
2929 obj.statusText = o.conn.statusText;
2930 obj.getResponseHeader = headerObj;
2931 obj.getAllResponseHeaders = headerStr;
2932 obj.responseText = o.conn.responseText;
2933 obj.responseXML = o.conn.responseXML;
2935 if (typeof callbackArg !== undefined) {
2936 obj.argument = callbackArg;
2942 createExceptionObject:function(tId, callbackArg, isAbort)
2945 var COMM_ERROR = 'communication failure';
2946 var ABORT_CODE = -1;
2947 var ABORT_ERROR = 'transaction aborted';
2953 obj.status = ABORT_CODE;
2954 obj.statusText = ABORT_ERROR;
2957 obj.status = COMM_CODE;
2958 obj.statusText = COMM_ERROR;
2962 obj.argument = callbackArg;
2968 initHeader:function(label, value, isDefault)
2970 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2972 if (headerObj[label] === undefined) {
2973 headerObj[label] = value;
2978 headerObj[label] = value + "," + headerObj[label];
2982 this.hasDefaultHeaders = true;
2985 this.hasHeaders = true;
2990 setHeader:function(o)
2992 if (this.hasDefaultHeaders) {
2993 for (var prop in this.defaultHeaders) {
2994 if (this.defaultHeaders.hasOwnProperty(prop)) {
2995 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3000 if (this.hasHeaders) {
3001 for (var prop in this.headers) {
3002 if (this.headers.hasOwnProperty(prop)) {
3003 o.conn.setRequestHeader(prop, this.headers[prop]);
3007 this.hasHeaders = false;
3011 resetDefaultHeaders:function() {
3012 delete this.defaultHeaders;
3013 this.defaultHeaders = {};
3014 this.hasDefaultHeaders = false;
3017 abort:function(o, callback, isTimeout)
3019 if(this.isCallInProgress(o)) {
3021 window.clearInterval(this.poll[o.tId]);
3022 delete this.poll[o.tId];
3024 delete this.timeout[o.tId];
3027 this.handleTransactionResponse(o, callback, true);
3037 isCallInProgress:function(o)
3040 return o.conn.readyState != 4 && o.conn.readyState != 0;
3049 releaseObject:function(o)
3058 'MSXML2.XMLHTTP.3.0',
3066 * Portions of this file are based on pieces of Yahoo User Interface Library
3067 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3068 * YUI licensed under the BSD License:
3069 * http://developer.yahoo.net/yui/license.txt
3070 * <script type="text/javascript">
3074 Roo.lib.Region = function(t, r, b, l) {
3084 Roo.lib.Region.prototype = {
3085 contains : function(region) {
3086 return ( region.left >= this.left &&
3087 region.right <= this.right &&
3088 region.top >= this.top &&
3089 region.bottom <= this.bottom );
3093 getArea : function() {
3094 return ( (this.bottom - this.top) * (this.right - this.left) );
3097 intersect : function(region) {
3098 var t = Math.max(this.top, region.top);
3099 var r = Math.min(this.right, region.right);
3100 var b = Math.min(this.bottom, region.bottom);
3101 var l = Math.max(this.left, region.left);
3103 if (b >= t && r >= l) {
3104 return new Roo.lib.Region(t, r, b, l);
3109 union : function(region) {
3110 var t = Math.min(this.top, region.top);
3111 var r = Math.max(this.right, region.right);
3112 var b = Math.max(this.bottom, region.bottom);
3113 var l = Math.min(this.left, region.left);
3115 return new Roo.lib.Region(t, r, b, l);
3118 adjust : function(t, l, b, r) {
3127 Roo.lib.Region.getRegion = function(el) {
3128 var p = Roo.lib.Dom.getXY(el);
3131 var r = p[0] + el.offsetWidth;
3132 var b = p[1] + el.offsetHeight;
3135 return new Roo.lib.Region(t, r, b, l);
3138 * Portions of this file are based on pieces of Yahoo User Interface Library
3139 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3140 * YUI licensed under the BSD License:
3141 * http://developer.yahoo.net/yui/license.txt
3142 * <script type="text/javascript">
3145 //@@dep Roo.lib.Region
3148 Roo.lib.Point = function(x, y) {
3149 if (x instanceof Array) {
3153 this.x = this.right = this.left = this[0] = x;
3154 this.y = this.top = this.bottom = this[1] = y;
3157 Roo.lib.Point.prototype = new Roo.lib.Region();
3159 * Portions of this file are based on pieces of Yahoo User Interface Library
3160 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3161 * YUI licensed under the BSD License:
3162 * http://developer.yahoo.net/yui/license.txt
3163 * <script type="text/javascript">
3170 scroll : function(el, args, duration, easing, cb, scope) {
3171 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3174 motion : function(el, args, duration, easing, cb, scope) {
3175 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3178 color : function(el, args, duration, easing, cb, scope) {
3179 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3182 run : function(el, args, duration, easing, cb, scope, type) {
3183 type = type || Roo.lib.AnimBase;
3184 if (typeof easing == "string") {
3185 easing = Roo.lib.Easing[easing];
3187 var anim = new type(el, args, duration, easing);
3188 anim.animateX(function() {
3189 Roo.callback(cb, scope);
3195 * Portions of this file are based on pieces of Yahoo User Interface Library
3196 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3197 * YUI licensed under the BSD License:
3198 * http://developer.yahoo.net/yui/license.txt
3199 * <script type="text/javascript">
3207 if (!libFlyweight) {
3208 libFlyweight = new Roo.Element.Flyweight();
3210 libFlyweight.dom = el;
3211 return libFlyweight;
3214 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3218 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3220 this.init(el, attributes, duration, method);
3224 Roo.lib.AnimBase.fly = fly;
3228 Roo.lib.AnimBase.prototype = {
3230 toString: function() {
3231 var el = this.getEl();
3232 var id = el.id || el.tagName;
3233 return ("Anim " + id);
3237 noNegatives: /width|height|opacity|padding/i,
3238 offsetAttribute: /^((width|height)|(top|left))$/,
3239 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3240 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3244 doMethod: function(attr, start, end) {
3245 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3249 setAttribute: function(attr, val, unit) {
3250 if (this.patterns.noNegatives.test(attr)) {
3251 val = (val > 0) ? val : 0;
3254 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3258 getAttribute: function(attr) {
3259 var el = this.getEl();
3260 var val = fly(el).getStyle(attr);
3262 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3263 return parseFloat(val);
3266 var a = this.patterns.offsetAttribute.exec(attr) || [];
3267 var pos = !!( a[3] );
3268 var box = !!( a[2] );
3271 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3272 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3281 getDefaultUnit: function(attr) {
3282 if (this.patterns.defaultUnit.test(attr)) {
3289 animateX : function(callback, scope) {
3290 var f = function() {
3291 this.onComplete.removeListener(f);
3292 if (typeof callback == "function") {
3293 callback.call(scope || this, this);
3296 this.onComplete.addListener(f, this);
3301 setRuntimeAttribute: function(attr) {
3304 var attributes = this.attributes;
3306 this.runtimeAttributes[attr] = {};
3308 var isset = function(prop) {
3309 return (typeof prop !== 'undefined');
3312 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3316 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3319 if (isset(attributes[attr]['to'])) {
3320 end = attributes[attr]['to'];
3321 } else if (isset(attributes[attr]['by'])) {
3322 if (start.constructor == Array) {
3324 for (var i = 0, len = start.length; i < len; ++i) {
3325 end[i] = start[i] + attributes[attr]['by'][i];
3328 end = start + attributes[attr]['by'];
3332 this.runtimeAttributes[attr].start = start;
3333 this.runtimeAttributes[attr].end = end;
3336 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3340 init: function(el, attributes, duration, method) {
3342 var isAnimated = false;
3345 var startTime = null;
3348 var actualFrames = 0;
3351 el = Roo.getDom(el);
3354 this.attributes = attributes || {};
3357 this.duration = duration || 1;
3360 this.method = method || Roo.lib.Easing.easeNone;
3363 this.useSeconds = true;
3366 this.currentFrame = 0;
3369 this.totalFrames = Roo.lib.AnimMgr.fps;
3372 this.getEl = function() {
3377 this.isAnimated = function() {
3382 this.getStartTime = function() {
3386 this.runtimeAttributes = {};
3389 this.animate = function() {
3390 if (this.isAnimated()) {
3394 this.currentFrame = 0;
3396 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3398 Roo.lib.AnimMgr.registerElement(this);
3402 this.stop = function(finish) {
3404 this.currentFrame = this.totalFrames;
3405 this._onTween.fire();
3407 Roo.lib.AnimMgr.stop(this);
3410 var onStart = function() {
3411 this.onStart.fire();
3413 this.runtimeAttributes = {};
3414 for (var attr in this.attributes) {
3415 this.setRuntimeAttribute(attr);
3420 startTime = new Date();
3424 var onTween = function() {
3426 duration: new Date() - this.getStartTime(),
3427 currentFrame: this.currentFrame
3430 data.toString = function() {
3432 'duration: ' + data.duration +
3433 ', currentFrame: ' + data.currentFrame
3437 this.onTween.fire(data);
3439 var runtimeAttributes = this.runtimeAttributes;
3441 for (var attr in runtimeAttributes) {
3442 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3448 var onComplete = function() {
3449 var actual_duration = (new Date() - startTime) / 1000 ;
3452 duration: actual_duration,
3453 frames: actualFrames,
3454 fps: actualFrames / actual_duration
3457 data.toString = function() {
3459 'duration: ' + data.duration +
3460 ', frames: ' + data.frames +
3461 ', fps: ' + data.fps
3467 this.onComplete.fire(data);
3471 this._onStart = new Roo.util.Event(this);
3472 this.onStart = new Roo.util.Event(this);
3473 this.onTween = new Roo.util.Event(this);
3474 this._onTween = new Roo.util.Event(this);
3475 this.onComplete = new Roo.util.Event(this);
3476 this._onComplete = new Roo.util.Event(this);
3477 this._onStart.addListener(onStart);
3478 this._onTween.addListener(onTween);
3479 this._onComplete.addListener(onComplete);
3484 * Portions of this file are based on pieces of Yahoo User Interface Library
3485 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3486 * YUI licensed under the BSD License:
3487 * http://developer.yahoo.net/yui/license.txt
3488 * <script type="text/javascript">
3492 Roo.lib.AnimMgr = new function() {
3509 this.registerElement = function(tween) {
3510 queue[queue.length] = tween;
3512 tween._onStart.fire();
3517 this.unRegister = function(tween, index) {
3518 tween._onComplete.fire();
3519 index = index || getIndex(tween);
3521 queue.splice(index, 1);
3525 if (tweenCount <= 0) {
3531 this.start = function() {
3532 if (thread === null) {
3533 thread = setInterval(this.run, this.delay);
3538 this.stop = function(tween) {
3540 clearInterval(thread);
3542 for (var i = 0, len = queue.length; i < len; ++i) {
3543 if (queue[0].isAnimated()) {
3544 this.unRegister(queue[0], 0);
3553 this.unRegister(tween);
3558 this.run = function() {
3559 for (var i = 0, len = queue.length; i < len; ++i) {
3560 var tween = queue[i];
3561 if (!tween || !tween.isAnimated()) {
3565 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3567 tween.currentFrame += 1;
3569 if (tween.useSeconds) {
3570 correctFrame(tween);
3572 tween._onTween.fire();
3575 Roo.lib.AnimMgr.stop(tween, i);
3580 var getIndex = function(anim) {
3581 for (var i = 0, len = queue.length; i < len; ++i) {
3582 if (queue[i] == anim) {
3590 var correctFrame = function(tween) {
3591 var frames = tween.totalFrames;
3592 var frame = tween.currentFrame;
3593 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3594 var elapsed = (new Date() - tween.getStartTime());
3597 if (elapsed < tween.duration * 1000) {
3598 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3600 tweak = frames - (frame + 1);
3602 if (tweak > 0 && isFinite(tweak)) {
3603 if (tween.currentFrame + tweak >= frames) {
3604 tweak = frames - (frame + 1);
3607 tween.currentFrame += tweak;
3613 * Portions of this file are based on pieces of Yahoo User Interface Library
3614 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3615 * YUI licensed under the BSD License:
3616 * http://developer.yahoo.net/yui/license.txt
3617 * <script type="text/javascript">
3620 Roo.lib.Bezier = new function() {
3622 this.getPosition = function(points, t) {
3623 var n = points.length;
3626 for (var i = 0; i < n; ++i) {
3627 tmp[i] = [points[i][0], points[i][1]];
3630 for (var j = 1; j < n; ++j) {
3631 for (i = 0; i < n - j; ++i) {
3632 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3633 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3637 return [ tmp[0][0], tmp[0][1] ];
3641 * Portions of this file are based on pieces of Yahoo User Interface Library
3642 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3643 * YUI licensed under the BSD License:
3644 * http://developer.yahoo.net/yui/license.txt
3645 * <script type="text/javascript">
3650 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3651 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3654 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3656 var fly = Roo.lib.AnimBase.fly;
3658 var superclass = Y.ColorAnim.superclass;
3659 var proto = Y.ColorAnim.prototype;
3661 proto.toString = function() {
3662 var el = this.getEl();
3663 var id = el.id || el.tagName;
3664 return ("ColorAnim " + id);
3667 proto.patterns.color = /color$/i;
3668 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3669 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3670 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3671 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3674 proto.parseColor = function(s) {
3675 if (s.length == 3) {
3679 var c = this.patterns.hex.exec(s);
3680 if (c && c.length == 4) {
3681 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3684 c = this.patterns.rgb.exec(s);
3685 if (c && c.length == 4) {
3686 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3689 c = this.patterns.hex3.exec(s);
3690 if (c && c.length == 4) {
3691 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3696 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3697 proto.getAttribute = function(attr) {
3698 var el = this.getEl();
3699 if (this.patterns.color.test(attr)) {
3700 var val = fly(el).getStyle(attr);
3702 if (this.patterns.transparent.test(val)) {
3703 var parent = el.parentNode;
3704 val = fly(parent).getStyle(attr);
3706 while (parent && this.patterns.transparent.test(val)) {
3707 parent = parent.parentNode;
3708 val = fly(parent).getStyle(attr);
3709 if (parent.tagName.toUpperCase() == 'HTML') {
3715 val = superclass.getAttribute.call(this, attr);
3720 proto.getAttribute = function(attr) {
3721 var el = this.getEl();
3722 if (this.patterns.color.test(attr)) {
3723 var val = fly(el).getStyle(attr);
3725 if (this.patterns.transparent.test(val)) {
3726 var parent = el.parentNode;
3727 val = fly(parent).getStyle(attr);
3729 while (parent && this.patterns.transparent.test(val)) {
3730 parent = parent.parentNode;
3731 val = fly(parent).getStyle(attr);
3732 if (parent.tagName.toUpperCase() == 'HTML') {
3738 val = superclass.getAttribute.call(this, attr);
3744 proto.doMethod = function(attr, start, end) {
3747 if (this.patterns.color.test(attr)) {
3749 for (var i = 0, len = start.length; i < len; ++i) {
3750 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3753 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3756 val = superclass.doMethod.call(this, attr, start, end);
3762 proto.setRuntimeAttribute = function(attr) {
3763 superclass.setRuntimeAttribute.call(this, attr);
3765 if (this.patterns.color.test(attr)) {
3766 var attributes = this.attributes;
3767 var start = this.parseColor(this.runtimeAttributes[attr].start);
3768 var end = this.parseColor(this.runtimeAttributes[attr].end);
3770 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3771 end = this.parseColor(attributes[attr].by);
3773 for (var i = 0, len = start.length; i < len; ++i) {
3774 end[i] = start[i] + end[i];
3778 this.runtimeAttributes[attr].start = start;
3779 this.runtimeAttributes[attr].end = end;
3785 * Portions of this file are based on pieces of Yahoo User Interface Library
3786 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3787 * YUI licensed under the BSD License:
3788 * http://developer.yahoo.net/yui/license.txt
3789 * <script type="text/javascript">
3795 easeNone: function (t, b, c, d) {
3796 return c * t / d + b;
3800 easeIn: function (t, b, c, d) {
3801 return c * (t /= d) * t + b;
3805 easeOut: function (t, b, c, d) {
3806 return -c * (t /= d) * (t - 2) + b;
3810 easeBoth: function (t, b, c, d) {
3811 if ((t /= d / 2) < 1) {
3812 return c / 2 * t * t + b;
3815 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3819 easeInStrong: function (t, b, c, d) {
3820 return c * (t /= d) * t * t * t + b;
3824 easeOutStrong: function (t, b, c, d) {
3825 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3829 easeBothStrong: function (t, b, c, d) {
3830 if ((t /= d / 2) < 1) {
3831 return c / 2 * t * t * t * t + b;
3834 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3839 elasticIn: function (t, b, c, d, a, p) {
3843 if ((t /= d) == 1) {
3850 if (!a || a < Math.abs(c)) {
3855 var s = p / (2 * Math.PI) * Math.asin(c / a);
3858 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3862 elasticOut: function (t, b, c, d, a, p) {
3866 if ((t /= d) == 1) {
3873 if (!a || a < Math.abs(c)) {
3878 var s = p / (2 * Math.PI) * Math.asin(c / a);
3881 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3885 elasticBoth: function (t, b, c, d, a, p) {
3890 if ((t /= d / 2) == 2) {
3898 if (!a || a < Math.abs(c)) {
3903 var s = p / (2 * Math.PI) * Math.asin(c / a);
3907 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3908 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3910 return a * Math.pow(2, -10 * (t -= 1)) *
3911 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3916 backIn: function (t, b, c, d, s) {
3917 if (typeof s == 'undefined') {
3920 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3924 backOut: function (t, b, c, d, s) {
3925 if (typeof s == 'undefined') {
3928 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3932 backBoth: function (t, b, c, d, s) {
3933 if (typeof s == 'undefined') {
3937 if ((t /= d / 2 ) < 1) {
3938 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3940 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3944 bounceIn: function (t, b, c, d) {
3945 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3949 bounceOut: function (t, b, c, d) {
3950 if ((t /= d) < (1 / 2.75)) {
3951 return c * (7.5625 * t * t) + b;
3952 } else if (t < (2 / 2.75)) {
3953 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3954 } else if (t < (2.5 / 2.75)) {
3955 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3957 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3961 bounceBoth: function (t, b, c, d) {
3963 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3965 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3968 * Portions of this file are based on pieces of Yahoo User Interface Library
3969 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3970 * YUI licensed under the BSD License:
3971 * http://developer.yahoo.net/yui/license.txt
3972 * <script type="text/javascript">
3976 Roo.lib.Motion = function(el, attributes, duration, method) {
3978 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3982 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3986 var superclass = Y.Motion.superclass;
3987 var proto = Y.Motion.prototype;
3989 proto.toString = function() {
3990 var el = this.getEl();
3991 var id = el.id || el.tagName;
3992 return ("Motion " + id);
3995 proto.patterns.points = /^points$/i;
3997 proto.setAttribute = function(attr, val, unit) {
3998 if (this.patterns.points.test(attr)) {
3999 unit = unit || 'px';
4000 superclass.setAttribute.call(this, 'left', val[0], unit);
4001 superclass.setAttribute.call(this, 'top', val[1], unit);
4003 superclass.setAttribute.call(this, attr, val, unit);
4007 proto.getAttribute = function(attr) {
4008 if (this.patterns.points.test(attr)) {
4010 superclass.getAttribute.call(this, 'left'),
4011 superclass.getAttribute.call(this, 'top')
4014 val = superclass.getAttribute.call(this, attr);
4020 proto.doMethod = function(attr, start, end) {
4023 if (this.patterns.points.test(attr)) {
4024 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4025 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4027 val = superclass.doMethod.call(this, attr, start, end);
4032 proto.setRuntimeAttribute = function(attr) {
4033 if (this.patterns.points.test(attr)) {
4034 var el = this.getEl();
4035 var attributes = this.attributes;
4037 var control = attributes['points']['control'] || [];
4041 if (control.length > 0 && !(control[0] instanceof Array)) {
4042 control = [control];
4045 for (i = 0,len = control.length; i < len; ++i) {
4046 tmp[i] = control[i];
4051 Roo.fly(el).position();
4053 if (isset(attributes['points']['from'])) {
4054 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4057 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4060 start = this.getAttribute('points');
4063 if (isset(attributes['points']['to'])) {
4064 end = translateValues.call(this, attributes['points']['to'], start);
4066 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4067 for (i = 0,len = control.length; i < len; ++i) {
4068 control[i] = translateValues.call(this, control[i], start);
4072 } else if (isset(attributes['points']['by'])) {
4073 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4075 for (i = 0,len = control.length; i < len; ++i) {
4076 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4080 this.runtimeAttributes[attr] = [start];
4082 if (control.length > 0) {
4083 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4086 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4089 superclass.setRuntimeAttribute.call(this, attr);
4093 var translateValues = function(val, start) {
4094 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4095 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4100 var isset = function(prop) {
4101 return (typeof prop !== 'undefined');
4105 * Portions of this file are based on pieces of Yahoo User Interface Library
4106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4107 * YUI licensed under the BSD License:
4108 * http://developer.yahoo.net/yui/license.txt
4109 * <script type="text/javascript">
4113 Roo.lib.Scroll = function(el, attributes, duration, method) {
4115 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4119 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4123 var superclass = Y.Scroll.superclass;
4124 var proto = Y.Scroll.prototype;
4126 proto.toString = function() {
4127 var el = this.getEl();
4128 var id = el.id || el.tagName;
4129 return ("Scroll " + id);
4132 proto.doMethod = function(attr, start, end) {
4135 if (attr == 'scroll') {
4137 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4138 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4142 val = superclass.doMethod.call(this, attr, start, end);
4147 proto.getAttribute = function(attr) {
4149 var el = this.getEl();
4151 if (attr == 'scroll') {
4152 val = [ el.scrollLeft, el.scrollTop ];
4154 val = superclass.getAttribute.call(this, attr);
4160 proto.setAttribute = function(attr, val, unit) {
4161 var el = this.getEl();
4163 if (attr == 'scroll') {
4164 el.scrollLeft = val[0];
4165 el.scrollTop = val[1];
4167 superclass.setAttribute.call(this, attr, val, unit);
4173 * Ext JS Library 1.1.1
4174 * Copyright(c) 2006-2007, Ext JS, LLC.
4176 * Originally Released Under LGPL - original licence link has changed is not relivant.
4179 * <script type="text/javascript">
4183 // nasty IE9 hack - what a pile of crap that is..
4185 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4186 Range.prototype.createContextualFragment = function (html) {
4187 var doc = window.document;
4188 var container = doc.createElement("div");
4189 container.innerHTML = html;
4190 var frag = doc.createDocumentFragment(), n;
4191 while ((n = container.firstChild)) {
4192 frag.appendChild(n);
4199 * @class Roo.DomHelper
4200 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4201 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4204 Roo.DomHelper = function(){
4205 var tempTableEl = null;
4206 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4207 var tableRe = /^table|tbody|tr|td$/i;
4209 // build as innerHTML where available
4211 var createHtml = function(o){
4212 if(typeof o == 'string'){
4221 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4222 if(attr == "style"){
4224 if(typeof s == "function"){
4227 if(typeof s == "string"){
4228 b += ' style="' + s + '"';
4229 }else if(typeof s == "object"){
4232 if(typeof s[key] != "function"){
4233 b += key + ":" + s[key] + ";";
4240 b += ' class="' + o["cls"] + '"';
4241 }else if(attr == "htmlFor"){
4242 b += ' for="' + o["htmlFor"] + '"';
4244 b += " " + attr + '="' + o[attr] + '"';
4248 if(emptyTags.test(o.tag)){
4252 var cn = o.children || o.cn;
4254 //http://bugs.kde.org/show_bug.cgi?id=71506
4255 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4256 for(var i = 0, len = cn.length; i < len; i++) {
4257 b += createHtml(cn[i], b);
4260 b += createHtml(cn, b);
4266 b += "</" + o.tag + ">";
4273 var createDom = function(o, parentNode){
4275 // defininition craeted..
4277 if (o.ns && o.ns != 'html') {
4279 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4280 xmlns[o.ns] = o.xmlns;
4283 if (typeof(xmlns[o.ns]) == 'undefined') {
4284 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4290 if (typeof(o) == 'string') {
4291 return parentNode.appendChild(document.createTextNode(o));
4293 o.tag = o.tag || div;
4294 if (o.ns && Roo.isIE) {
4296 o.tag = o.ns + ':' + o.tag;
4299 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4300 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4303 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4304 attr == "style" || typeof o[attr] == "function") { continue; }
4306 if(attr=="cls" && Roo.isIE){
4307 el.className = o["cls"];
4309 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4315 Roo.DomHelper.applyStyles(el, o.style);
4316 var cn = o.children || o.cn;
4318 //http://bugs.kde.org/show_bug.cgi?id=71506
4319 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4320 for(var i = 0, len = cn.length; i < len; i++) {
4321 createDom(cn[i], el);
4328 el.innerHTML = o.html;
4331 parentNode.appendChild(el);
4336 var ieTable = function(depth, s, h, e){
4337 tempTableEl.innerHTML = [s, h, e].join('');
4338 var i = -1, el = tempTableEl;
4345 // kill repeat to save bytes
4349 tbe = '</tbody>'+te,
4355 * Nasty code for IE's broken table implementation
4357 var insertIntoTable = function(tag, where, el, html){
4359 tempTableEl = document.createElement('div');
4364 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4367 if(where == 'beforebegin'){
4371 before = el.nextSibling;
4374 node = ieTable(4, trs, html, tre);
4376 else if(tag == 'tr'){
4377 if(where == 'beforebegin'){
4380 node = ieTable(3, tbs, html, tbe);
4381 } else if(where == 'afterend'){
4382 before = el.nextSibling;
4384 node = ieTable(3, tbs, html, tbe);
4385 } else{ // INTO a TR
4386 if(where == 'afterbegin'){
4387 before = el.firstChild;
4389 node = ieTable(4, trs, html, tre);
4391 } else if(tag == 'tbody'){
4392 if(where == 'beforebegin'){
4395 node = ieTable(2, ts, html, te);
4396 } else if(where == 'afterend'){
4397 before = el.nextSibling;
4399 node = ieTable(2, ts, html, te);
4401 if(where == 'afterbegin'){
4402 before = el.firstChild;
4404 node = ieTable(3, tbs, html, tbe);
4407 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4410 if(where == 'afterbegin'){
4411 before = el.firstChild;
4413 node = ieTable(2, ts, html, te);
4415 el.insertBefore(node, before);
4420 /** True to force the use of DOM instead of html fragments @type Boolean */
4424 * Returns the markup for the passed Element(s) config
4425 * @param {Object} o The Dom object spec (and children)
4428 markup : function(o){
4429 return createHtml(o);
4433 * Applies a style specification to an element
4434 * @param {String/HTMLElement} el The element to apply styles to
4435 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4436 * a function which returns such a specification.
4438 applyStyles : function(el, styles){
4441 if(typeof styles == "string"){
4442 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4444 while ((matches = re.exec(styles)) != null){
4445 el.setStyle(matches[1], matches[2]);
4447 }else if (typeof styles == "object"){
4448 for (var style in styles){
4449 el.setStyle(style, styles[style]);
4451 }else if (typeof styles == "function"){
4452 Roo.DomHelper.applyStyles(el, styles.call());
4458 * Inserts an HTML fragment into the Dom
4459 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4460 * @param {HTMLElement} el The context element
4461 * @param {String} html The HTML fragmenet
4462 * @return {HTMLElement} The new node
4464 insertHtml : function(where, el, html){
4465 where = where.toLowerCase();
4466 if(el.insertAdjacentHTML){
4467 if(tableRe.test(el.tagName)){
4469 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4475 el.insertAdjacentHTML('BeforeBegin', html);
4476 return el.previousSibling;
4478 el.insertAdjacentHTML('AfterBegin', html);
4479 return el.firstChild;
4481 el.insertAdjacentHTML('BeforeEnd', html);
4482 return el.lastChild;
4484 el.insertAdjacentHTML('AfterEnd', html);
4485 return el.nextSibling;
4487 throw 'Illegal insertion point -> "' + where + '"';
4489 var range = el.ownerDocument.createRange();
4493 range.setStartBefore(el);
4494 frag = range.createContextualFragment(html);
4495 el.parentNode.insertBefore(frag, el);
4496 return el.previousSibling;
4499 range.setStartBefore(el.firstChild);
4500 frag = range.createContextualFragment(html);
4501 el.insertBefore(frag, el.firstChild);
4502 return el.firstChild;
4504 el.innerHTML = html;
4505 return el.firstChild;
4509 range.setStartAfter(el.lastChild);
4510 frag = range.createContextualFragment(html);
4511 el.appendChild(frag);
4512 return el.lastChild;
4514 el.innerHTML = html;
4515 return el.lastChild;
4518 range.setStartAfter(el);
4519 frag = range.createContextualFragment(html);
4520 el.parentNode.insertBefore(frag, el.nextSibling);
4521 return el.nextSibling;
4523 throw 'Illegal insertion point -> "' + where + '"';
4527 * Creates new Dom element(s) and inserts them before el
4528 * @param {String/HTMLElement/Element} el The context element
4529 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531 * @return {HTMLElement/Roo.Element} The new node
4533 insertBefore : function(el, o, returnElement){
4534 return this.doInsert(el, o, returnElement, "beforeBegin");
4538 * Creates new Dom element(s) and inserts them after el
4539 * @param {String/HTMLElement/Element} el The context element
4540 * @param {Object} o The Dom object spec (and children)
4541 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4542 * @return {HTMLElement/Roo.Element} The new node
4544 insertAfter : function(el, o, returnElement){
4545 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4549 * Creates new Dom element(s) and inserts them as the first child of el
4550 * @param {String/HTMLElement/Element} el The context element
4551 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4552 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4553 * @return {HTMLElement/Roo.Element} The new node
4555 insertFirst : function(el, o, returnElement){
4556 return this.doInsert(el, o, returnElement, "afterBegin");
4560 doInsert : function(el, o, returnElement, pos, sibling){
4561 el = Roo.getDom(el);
4563 if(this.useDom || o.ns){
4564 newNode = createDom(o, null);
4565 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4567 var html = createHtml(o);
4568 newNode = this.insertHtml(pos, el, html);
4570 return returnElement ? Roo.get(newNode, true) : newNode;
4574 * Creates new Dom element(s) and appends them to el
4575 * @param {String/HTMLElement/Element} el The context element
4576 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4577 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4578 * @return {HTMLElement/Roo.Element} The new node
4580 append : function(el, o, returnElement){
4581 el = Roo.getDom(el);
4583 if(this.useDom || o.ns){
4584 newNode = createDom(o, null);
4585 el.appendChild(newNode);
4587 var html = createHtml(o);
4588 newNode = this.insertHtml("beforeEnd", el, html);
4590 return returnElement ? Roo.get(newNode, true) : newNode;
4594 * Creates new Dom element(s) and overwrites the contents of el with them
4595 * @param {String/HTMLElement/Element} el The context element
4596 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4597 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4598 * @return {HTMLElement/Roo.Element} The new node
4600 overwrite : function(el, o, returnElement){
4601 el = Roo.getDom(el);
4604 while (el.childNodes.length) {
4605 el.removeChild(el.firstChild);
4609 el.innerHTML = createHtml(o);
4612 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4616 * Creates a new Roo.DomHelper.Template from the Dom object spec
4617 * @param {Object} o The Dom object spec (and children)
4618 * @return {Roo.DomHelper.Template} The new template
4620 createTemplate : function(o){
4621 var html = createHtml(o);
4622 return new Roo.Template(html);
4628 * Ext JS Library 1.1.1
4629 * Copyright(c) 2006-2007, Ext JS, LLC.
4631 * Originally Released Under LGPL - original licence link has changed is not relivant.
4634 * <script type="text/javascript">
4638 * @class Roo.Template
4639 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4640 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4643 var t = new Roo.Template({
4644 html : '<div name="{id}">' +
4645 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4647 myformat: function (value, allValues) {
4648 return 'XX' + value;
4651 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4653 * For more information see this blog post with examples:
4654 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4655 - Create Elements using DOM, HTML fragments and Templates</a>.
4657 * @param {Object} cfg - Configuration object.
4659 Roo.Template = function(cfg){
4661 if(cfg instanceof Array){
4663 }else if(arguments.length > 1){
4664 cfg = Array.prototype.join.call(arguments, "");
4668 if (typeof(cfg) == 'object') {
4679 Roo.Template.prototype = {
4682 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
4688 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4689 * it should be fixed so that template is observable...
4693 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4701 * Returns an HTML fragment of this template with the specified values applied.
4702 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4703 * @return {String} The HTML fragment
4708 applyTemplate : function(values){
4709 //Roo.log(["applyTemplate", values]);
4713 return this.compiled(values);
4715 var useF = this.disableFormats !== true;
4716 var fm = Roo.util.Format, tpl = this;
4717 var fn = function(m, name, format, args){
4719 if(format.substr(0, 5) == "this."){
4720 return tpl.call(format.substr(5), values[name], values);
4723 // quoted values are required for strings in compiled templates,
4724 // but for non compiled we need to strip them
4725 // quoted reversed for jsmin
4726 var re = /^\s*['"](.*)["']\s*$/;
4727 args = args.split(',');
4728 for(var i = 0, len = args.length; i < len; i++){
4729 args[i] = args[i].replace(re, "$1");
4731 args = [values[name]].concat(args);
4733 args = [values[name]];
4735 return fm[format].apply(fm, args);
4738 return values[name] !== undefined ? values[name] : "";
4741 return this.html.replace(this.re, fn);
4759 this.loading = true;
4760 this.compiled = false;
4762 var cx = new Roo.data.Connection();
4766 success : function (response) {
4770 _t.set(response.responseText,true);
4776 failure : function(response) {
4777 Roo.log("Template failed to load from " + _t.url);
4784 * Sets the HTML used as the template and optionally compiles it.
4785 * @param {String} html
4786 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4787 * @return {Roo.Template} this
4789 set : function(html, compile){
4791 this.compiled = false;
4799 * True to disable format functions (defaults to false)
4802 disableFormats : false,
4805 * The regular expression used to match template variables
4809 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4812 * Compiles the template into an internal function, eliminating the RegEx overhead.
4813 * @return {Roo.Template} this
4815 compile : function(){
4816 var fm = Roo.util.Format;
4817 var useF = this.disableFormats !== true;
4818 var sep = Roo.isGecko ? "+" : ",";
4819 var fn = function(m, name, format, args){
4821 args = args ? ',' + args : "";
4822 if(format.substr(0, 5) != "this."){
4823 format = "fm." + format + '(';
4825 format = 'this.call("'+ format.substr(5) + '", ';
4829 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4831 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4834 // branched to use + in gecko and [].join() in others
4836 body = "this.compiled = function(values){ return '" +
4837 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4840 body = ["this.compiled = function(values){ return ['"];
4841 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4842 body.push("'].join('');};");
4843 body = body.join('');
4853 // private function used to call members
4854 call : function(fnName, value, allValues){
4855 return this[fnName](value, allValues);
4859 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4860 * @param {String/HTMLElement/Roo.Element} el The context element
4861 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4862 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4863 * @return {HTMLElement/Roo.Element} The new node or Element
4865 insertFirst: function(el, values, returnElement){
4866 return this.doInsert('afterBegin', el, values, returnElement);
4870 * Applies the supplied values to the template and inserts the new node(s) before el.
4871 * @param {String/HTMLElement/Roo.Element} el The context element
4872 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4873 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4874 * @return {HTMLElement/Roo.Element} The new node or Element
4876 insertBefore: function(el, values, returnElement){
4877 return this.doInsert('beforeBegin', el, values, returnElement);
4881 * Applies the supplied values to the template and inserts the new node(s) after el.
4882 * @param {String/HTMLElement/Roo.Element} el The context element
4883 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4884 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4885 * @return {HTMLElement/Roo.Element} The new node or Element
4887 insertAfter : function(el, values, returnElement){
4888 return this.doInsert('afterEnd', el, values, returnElement);
4892 * Applies the supplied values to the template and appends the new node(s) to el.
4893 * @param {String/HTMLElement/Roo.Element} el The context element
4894 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4895 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4896 * @return {HTMLElement/Roo.Element} The new node or Element
4898 append : function(el, values, returnElement){
4899 return this.doInsert('beforeEnd', el, values, returnElement);
4902 doInsert : function(where, el, values, returnEl){
4903 el = Roo.getDom(el);
4904 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4905 return returnEl ? Roo.get(newNode, true) : newNode;
4909 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4910 * @param {String/HTMLElement/Roo.Element} el The context element
4911 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4912 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4913 * @return {HTMLElement/Roo.Element} The new node or Element
4915 overwrite : function(el, values, returnElement){
4916 el = Roo.getDom(el);
4917 el.innerHTML = this.applyTemplate(values);
4918 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4922 * Alias for {@link #applyTemplate}
4925 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4928 Roo.DomHelper.Template = Roo.Template;
4931 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4932 * @param {String/HTMLElement} el A DOM element or its id
4933 * @returns {Roo.Template} The created template
4936 Roo.Template.from = function(el){
4937 el = Roo.getDom(el);
4938 return new Roo.Template(el.value || el.innerHTML);
4941 * Ext JS Library 1.1.1
4942 * Copyright(c) 2006-2007, Ext JS, LLC.
4944 * Originally Released Under LGPL - original licence link has changed is not relivant.
4947 * <script type="text/javascript">
4952 * This is code is also distributed under MIT license for use
4953 * with jQuery and prototype JavaScript libraries.
4956 * @class Roo.DomQuery
4957 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4959 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4962 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4964 <h4>Element Selectors:</h4>
4966 <li> <b>*</b> any element</li>
4967 <li> <b>E</b> an element with the tag E</li>
4968 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4969 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4970 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4971 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4973 <h4>Attribute Selectors:</h4>
4974 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4976 <li> <b>E[foo]</b> has an attribute "foo"</li>
4977 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4978 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4979 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4980 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4981 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4982 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4984 <h4>Pseudo Classes:</h4>
4986 <li> <b>E:first-child</b> E is the first child of its parent</li>
4987 <li> <b>E:last-child</b> E is the last child of its parent</li>
4988 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4989 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4990 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4991 <li> <b>E:only-child</b> E is the only child of its parent</li>
4992 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4993 <li> <b>E:first</b> the first E in the resultset</li>
4994 <li> <b>E:last</b> the last E in the resultset</li>
4995 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4996 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4997 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4998 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4999 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5000 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5001 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5002 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5003 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5005 <h4>CSS Value Selectors:</h4>
5007 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5008 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5009 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5010 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5011 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5012 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5016 Roo.DomQuery = function(){
5017 var cache = {}, simpleCache = {}, valueCache = {};
5018 var nonSpace = /\S/;
5019 var trimRe = /^\s+|\s+$/g;
5020 var tplRe = /\{(\d+)\}/g;
5021 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5022 var tagTokenRe = /^(#)?([\w-\*]+)/;
5023 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5025 function child(p, index){
5027 var n = p.firstChild;
5029 if(n.nodeType == 1){
5040 while((n = n.nextSibling) && n.nodeType != 1);
5045 while((n = n.previousSibling) && n.nodeType != 1);
5049 function children(d){
5050 var n = d.firstChild, ni = -1;
5052 var nx = n.nextSibling;
5053 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5063 function byClassName(c, a, v){
5067 var r = [], ri = -1, cn;
5068 for(var i = 0, ci; ci = c[i]; i++){
5069 if((' '+ci.className+' ').indexOf(v) != -1){
5076 function attrValue(n, attr){
5077 if(!n.tagName && typeof n.length != "undefined"){
5086 if(attr == "class" || attr == "className"){
5089 return n.getAttribute(attr) || n[attr];
5093 function getNodes(ns, mode, tagName){
5094 var result = [], ri = -1, cs;
5098 tagName = tagName || "*";
5099 if(typeof ns.getElementsByTagName != "undefined"){
5103 for(var i = 0, ni; ni = ns[i]; i++){
5104 cs = ni.getElementsByTagName(tagName);
5105 for(var j = 0, ci; ci = cs[j]; j++){
5109 }else if(mode == "/" || mode == ">"){
5110 var utag = tagName.toUpperCase();
5111 for(var i = 0, ni, cn; ni = ns[i]; i++){
5112 cn = ni.children || ni.childNodes;
5113 for(var j = 0, cj; cj = cn[j]; j++){
5114 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5119 }else if(mode == "+"){
5120 var utag = tagName.toUpperCase();
5121 for(var i = 0, n; n = ns[i]; i++){
5122 while((n = n.nextSibling) && n.nodeType != 1);
5123 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5127 }else if(mode == "~"){
5128 for(var i = 0, n; n = ns[i]; i++){
5129 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5138 function concat(a, b){
5142 for(var i = 0, l = b.length; i < l; i++){
5148 function byTag(cs, tagName){
5149 if(cs.tagName || cs == document){
5155 var r = [], ri = -1;
5156 tagName = tagName.toLowerCase();
5157 for(var i = 0, ci; ci = cs[i]; i++){
5158 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5165 function byId(cs, attr, id){
5166 if(cs.tagName || cs == document){
5172 var r = [], ri = -1;
5173 for(var i = 0,ci; ci = cs[i]; i++){
5174 if(ci && ci.id == id){
5182 function byAttribute(cs, attr, value, op, custom){
5183 var r = [], ri = -1, st = custom=="{";
5184 var f = Roo.DomQuery.operators[op];
5185 for(var i = 0, ci; ci = cs[i]; i++){
5188 a = Roo.DomQuery.getStyle(ci, attr);
5190 else if(attr == "class" || attr == "className"){
5192 }else if(attr == "for"){
5194 }else if(attr == "href"){
5195 a = ci.getAttribute("href", 2);
5197 a = ci.getAttribute(attr);
5199 if((f && f(a, value)) || (!f && a)){
5206 function byPseudo(cs, name, value){
5207 return Roo.DomQuery.pseudos[name](cs, value);
5210 // This is for IE MSXML which does not support expandos.
5211 // IE runs the same speed using setAttribute, however FF slows way down
5212 // and Safari completely fails so they need to continue to use expandos.
5213 var isIE = window.ActiveXObject ? true : false;
5215 // this eval is stop the compressor from
5216 // renaming the variable to something shorter
5218 /** eval:var:batch */
5223 function nodupIEXml(cs){
5225 cs[0].setAttribute("_nodup", d);
5227 for(var i = 1, len = cs.length; i < len; i++){
5229 if(!c.getAttribute("_nodup") != d){
5230 c.setAttribute("_nodup", d);
5234 for(var i = 0, len = cs.length; i < len; i++){
5235 cs[i].removeAttribute("_nodup");
5244 var len = cs.length, c, i, r = cs, cj, ri = -1;
5245 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5248 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5249 return nodupIEXml(cs);
5253 for(i = 1; c = cs[i]; i++){
5258 for(var j = 0; j < i; j++){
5261 for(j = i+1; cj = cs[j]; j++){
5273 function quickDiffIEXml(c1, c2){
5275 for(var i = 0, len = c1.length; i < len; i++){
5276 c1[i].setAttribute("_qdiff", d);
5279 for(var i = 0, len = c2.length; i < len; i++){
5280 if(c2[i].getAttribute("_qdiff") != d){
5281 r[r.length] = c2[i];
5284 for(var i = 0, len = c1.length; i < len; i++){
5285 c1[i].removeAttribute("_qdiff");
5290 function quickDiff(c1, c2){
5291 var len1 = c1.length;
5295 if(isIE && c1[0].selectSingleNode){
5296 return quickDiffIEXml(c1, c2);
5299 for(var i = 0; i < len1; i++){
5303 for(var i = 0, len = c2.length; i < len; i++){
5304 if(c2[i]._qdiff != d){
5305 r[r.length] = c2[i];
5311 function quickId(ns, mode, root, id){
5313 var d = root.ownerDocument || root;
5314 return d.getElementById(id);
5316 ns = getNodes(ns, mode, "*");
5317 return byId(ns, null, id);
5321 getStyle : function(el, name){
5322 return Roo.fly(el).getStyle(name);
5325 * Compiles a selector/xpath query into a reusable function. The returned function
5326 * takes one parameter "root" (optional), which is the context node from where the query should start.
5327 * @param {String} selector The selector/xpath query
5328 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5329 * @return {Function}
5331 compile : function(path, type){
5332 type = type || "select";
5334 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5335 var q = path, mode, lq;
5336 var tk = Roo.DomQuery.matchers;
5337 var tklen = tk.length;
5340 // accept leading mode switch
5341 var lmode = q.match(modeRe);
5342 if(lmode && lmode[1]){
5343 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5344 q = q.replace(lmode[1], "");
5346 // strip leading slashes
5347 while(path.substr(0, 1)=="/"){
5348 path = path.substr(1);
5351 while(q && lq != q){
5353 var tm = q.match(tagTokenRe);
5354 if(type == "select"){
5357 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5359 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5361 q = q.replace(tm[0], "");
5362 }else if(q.substr(0, 1) != '@'){
5363 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5368 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5370 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5372 q = q.replace(tm[0], "");
5375 while(!(mm = q.match(modeRe))){
5376 var matched = false;
5377 for(var j = 0; j < tklen; j++){
5379 var m = q.match(t.re);
5381 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5384 q = q.replace(m[0], "");
5389 // prevent infinite loop on bad selector
5391 throw 'Error parsing selector, parsing failed at "' + q + '"';
5395 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5396 q = q.replace(mm[1], "");
5399 fn[fn.length] = "return nodup(n);\n}";
5402 * list of variables that need from compression as they are used by eval.
5412 * eval:var:byClassName
5414 * eval:var:byAttribute
5415 * eval:var:attrValue
5423 * Selects a group of elements.
5424 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5425 * @param {Node} root (optional) The start of the query (defaults to document).
5428 select : function(path, root, type){
5429 if(!root || root == document){
5432 if(typeof root == "string"){
5433 root = document.getElementById(root);
5435 var paths = path.split(",");
5437 for(var i = 0, len = paths.length; i < len; i++){
5438 var p = paths[i].replace(trimRe, "");
5440 cache[p] = Roo.DomQuery.compile(p);
5442 throw p + " is not a valid selector";
5445 var result = cache[p](root);
5446 if(result && result != document){
5447 results = results.concat(result);
5450 if(paths.length > 1){
5451 return nodup(results);
5457 * Selects a single element.
5458 * @param {String} selector The selector/xpath query
5459 * @param {Node} root (optional) The start of the query (defaults to document).
5462 selectNode : function(path, root){
5463 return Roo.DomQuery.select(path, root)[0];
5467 * Selects the value of a node, optionally replacing null with the defaultValue.
5468 * @param {String} selector The selector/xpath query
5469 * @param {Node} root (optional) The start of the query (defaults to document).
5470 * @param {String} defaultValue
5472 selectValue : function(path, root, defaultValue){
5473 path = path.replace(trimRe, "");
5474 if(!valueCache[path]){
5475 valueCache[path] = Roo.DomQuery.compile(path, "select");
5477 var n = valueCache[path](root);
5478 n = n[0] ? n[0] : n;
5479 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5480 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5484 * Selects the value of a node, parsing integers and floats.
5485 * @param {String} selector The selector/xpath query
5486 * @param {Node} root (optional) The start of the query (defaults to document).
5487 * @param {Number} defaultValue
5490 selectNumber : function(path, root, defaultValue){
5491 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5492 return parseFloat(v);
5496 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5497 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5498 * @param {String} selector The simple selector to test
5501 is : function(el, ss){
5502 if(typeof el == "string"){
5503 el = document.getElementById(el);
5505 var isArray = (el instanceof Array);
5506 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5507 return isArray ? (result.length == el.length) : (result.length > 0);
5511 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5512 * @param {Array} el An array of elements to filter
5513 * @param {String} selector The simple selector to test
5514 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5515 * the selector instead of the ones that match
5518 filter : function(els, ss, nonMatches){
5519 ss = ss.replace(trimRe, "");
5520 if(!simpleCache[ss]){
5521 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5523 var result = simpleCache[ss](els);
5524 return nonMatches ? quickDiff(result, els) : result;
5528 * Collection of matching regular expressions and code snippets.
5532 select: 'n = byClassName(n, null, " {1} ");'
5534 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5535 select: 'n = byPseudo(n, "{1}", "{2}");'
5537 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5538 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5541 select: 'n = byId(n, null, "{1}");'
5544 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5549 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5550 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5553 "=" : function(a, v){
5556 "!=" : function(a, v){
5559 "^=" : function(a, v){
5560 return a && a.substr(0, v.length) == v;
5562 "$=" : function(a, v){
5563 return a && a.substr(a.length-v.length) == v;
5565 "*=" : function(a, v){
5566 return a && a.indexOf(v) !== -1;
5568 "%=" : function(a, v){
5569 return (a % v) == 0;
5571 "|=" : function(a, v){
5572 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5574 "~=" : function(a, v){
5575 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5580 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5581 * and the argument (if any) supplied in the selector.
5584 "first-child" : function(c){
5585 var r = [], ri = -1, n;
5586 for(var i = 0, ci; ci = n = c[i]; i++){
5587 while((n = n.previousSibling) && n.nodeType != 1);
5595 "last-child" : function(c){
5596 var r = [], ri = -1, n;
5597 for(var i = 0, ci; ci = n = c[i]; i++){
5598 while((n = n.nextSibling) && n.nodeType != 1);
5606 "nth-child" : function(c, a) {
5607 var r = [], ri = -1;
5608 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5609 var f = (m[1] || 1) - 0, l = m[2] - 0;
5610 for(var i = 0, n; n = c[i]; i++){
5611 var pn = n.parentNode;
5612 if (batch != pn._batch) {
5614 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5615 if(cn.nodeType == 1){
5622 if (l == 0 || n.nodeIndex == l){
5625 } else if ((n.nodeIndex + l) % f == 0){
5633 "only-child" : function(c){
5634 var r = [], ri = -1;;
5635 for(var i = 0, ci; ci = c[i]; i++){
5636 if(!prev(ci) && !next(ci)){
5643 "empty" : function(c){
5644 var r = [], ri = -1;
5645 for(var i = 0, ci; ci = c[i]; i++){
5646 var cns = ci.childNodes, j = 0, cn, empty = true;
5649 if(cn.nodeType == 1 || cn.nodeType == 3){
5661 "contains" : function(c, v){
5662 var r = [], ri = -1;
5663 for(var i = 0, ci; ci = c[i]; i++){
5664 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5671 "nodeValue" : function(c, v){
5672 var r = [], ri = -1;
5673 for(var i = 0, ci; ci = c[i]; i++){
5674 if(ci.firstChild && ci.firstChild.nodeValue == v){
5681 "checked" : function(c){
5682 var r = [], ri = -1;
5683 for(var i = 0, ci; ci = c[i]; i++){
5684 if(ci.checked == true){
5691 "not" : function(c, ss){
5692 return Roo.DomQuery.filter(c, ss, true);
5695 "odd" : function(c){
5696 return this["nth-child"](c, "odd");
5699 "even" : function(c){
5700 return this["nth-child"](c, "even");
5703 "nth" : function(c, a){
5704 return c[a-1] || [];
5707 "first" : function(c){
5711 "last" : function(c){
5712 return c[c.length-1] || [];
5715 "has" : function(c, ss){
5716 var s = Roo.DomQuery.select;
5717 var r = [], ri = -1;
5718 for(var i = 0, ci; ci = c[i]; i++){
5719 if(s(ss, ci).length > 0){
5726 "next" : function(c, ss){
5727 var is = Roo.DomQuery.is;
5728 var r = [], ri = -1;
5729 for(var i = 0, ci; ci = c[i]; i++){
5738 "prev" : function(c, ss){
5739 var is = Roo.DomQuery.is;
5740 var r = [], ri = -1;
5741 for(var i = 0, ci; ci = c[i]; i++){
5754 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5755 * @param {String} path The selector/xpath query
5756 * @param {Node} root (optional) The start of the query (defaults to document).
5761 Roo.query = Roo.DomQuery.select;
5764 * Ext JS Library 1.1.1
5765 * Copyright(c) 2006-2007, Ext JS, LLC.
5767 * Originally Released Under LGPL - original licence link has changed is not relivant.
5770 * <script type="text/javascript">
5774 * @class Roo.util.Observable
5775 * Base class that provides a common interface for publishing events. Subclasses are expected to
5776 * to have a property "events" with all the events defined.<br>
5779 Employee = function(name){
5786 Roo.extend(Employee, Roo.util.Observable);
5788 * @param {Object} config properties to use (incuding events / listeners)
5791 Roo.util.Observable = function(cfg){
5794 this.addEvents(cfg.events || {});
5796 delete cfg.events; // make sure
5799 Roo.apply(this, cfg);
5802 this.on(this.listeners);
5803 delete this.listeners;
5806 Roo.util.Observable.prototype = {
5808 * @cfg {Object} listeners list of events and functions to call for this object,
5812 'click' : function(e) {
5822 * Fires the specified event with the passed parameters (minus the event name).
5823 * @param {String} eventName
5824 * @param {Object...} args Variable number of parameters are passed to handlers
5825 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5827 fireEvent : function(){
5828 var ce = this.events[arguments[0].toLowerCase()];
5829 if(typeof ce == "object"){
5830 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5837 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5840 * Appends an event handler to this component
5841 * @param {String} eventName The type of event to listen for
5842 * @param {Function} handler The method the event invokes
5843 * @param {Object} scope (optional) The scope in which to execute the handler
5844 * function. The handler function's "this" context.
5845 * @param {Object} options (optional) An object containing handler configuration
5846 * properties. This may contain any of the following properties:<ul>
5847 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5848 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5849 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5850 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5851 * by the specified number of milliseconds. If the event fires again within that time, the original
5852 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5855 * <b>Combining Options</b><br>
5856 * Using the options argument, it is possible to combine different types of listeners:<br>
5858 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5860 el.on('click', this.onClick, this, {
5867 * <b>Attaching multiple handlers in 1 call</b><br>
5868 * The method also allows for a single argument to be passed which is a config object containing properties
5869 * which specify multiple handlers.
5878 fn: this.onMouseOver,
5882 fn: this.onMouseOut,
5888 * Or a shorthand syntax which passes the same scope object to all handlers:
5891 'click': this.onClick,
5892 'mouseover': this.onMouseOver,
5893 'mouseout': this.onMouseOut,
5898 addListener : function(eventName, fn, scope, o){
5899 if(typeof eventName == "object"){
5902 if(this.filterOptRe.test(e)){
5905 if(typeof o[e] == "function"){
5907 this.addListener(e, o[e], o.scope, o);
5909 // individual options
5910 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5915 o = (!o || typeof o == "boolean") ? {} : o;
5916 eventName = eventName.toLowerCase();
5917 var ce = this.events[eventName] || true;
5918 if(typeof ce == "boolean"){
5919 ce = new Roo.util.Event(this, eventName);
5920 this.events[eventName] = ce;
5922 ce.addListener(fn, scope, o);
5926 * Removes a listener
5927 * @param {String} eventName The type of event to listen for
5928 * @param {Function} handler The handler to remove
5929 * @param {Object} scope (optional) The scope (this object) for the handler
5931 removeListener : function(eventName, fn, scope){
5932 var ce = this.events[eventName.toLowerCase()];
5933 if(typeof ce == "object"){
5934 ce.removeListener(fn, scope);
5939 * Removes all listeners for this object
5941 purgeListeners : function(){
5942 for(var evt in this.events){
5943 if(typeof this.events[evt] == "object"){
5944 this.events[evt].clearListeners();
5949 relayEvents : function(o, events){
5950 var createHandler = function(ename){
5953 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5956 for(var i = 0, len = events.length; i < len; i++){
5957 var ename = events[i];
5958 if(!this.events[ename]){
5959 this.events[ename] = true;
5961 o.on(ename, createHandler(ename), this);
5966 * Used to define events on this Observable
5967 * @param {Object} object The object with the events defined
5969 addEvents : function(o){
5973 Roo.applyIf(this.events, o);
5977 * Checks to see if this object has any listeners for a specified event
5978 * @param {String} eventName The name of the event to check for
5979 * @return {Boolean} True if the event is being listened for, else false
5981 hasListener : function(eventName){
5982 var e = this.events[eventName];
5983 return typeof e == "object" && e.listeners.length > 0;
5987 * Appends an event handler to this element (shorthand for addListener)
5988 * @param {String} eventName The type of event to listen for
5989 * @param {Function} handler The method the event invokes
5990 * @param {Object} scope (optional) The scope in which to execute the handler
5991 * function. The handler function's "this" context.
5992 * @param {Object} options (optional)
5995 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5997 * Removes a listener (shorthand for removeListener)
5998 * @param {String} eventName The type of event to listen for
5999 * @param {Function} handler The handler to remove
6000 * @param {Object} scope (optional) The scope (this object) for the handler
6003 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6006 * Starts capture on the specified Observable. All events will be passed
6007 * to the supplied function with the event name + standard signature of the event
6008 * <b>before</b> the event is fired. If the supplied function returns false,
6009 * the event will not fire.
6010 * @param {Observable} o The Observable to capture
6011 * @param {Function} fn The function to call
6012 * @param {Object} scope (optional) The scope (this object) for the fn
6015 Roo.util.Observable.capture = function(o, fn, scope){
6016 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6020 * Removes <b>all</b> added captures from the Observable.
6021 * @param {Observable} o The Observable to release
6024 Roo.util.Observable.releaseCapture = function(o){
6025 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6030 var createBuffered = function(h, o, scope){
6031 var task = new Roo.util.DelayedTask();
6033 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6037 var createSingle = function(h, e, fn, scope){
6039 e.removeListener(fn, scope);
6040 return h.apply(scope, arguments);
6044 var createDelayed = function(h, o, scope){
6046 var args = Array.prototype.slice.call(arguments, 0);
6047 setTimeout(function(){
6048 h.apply(scope, args);
6053 Roo.util.Event = function(obj, name){
6056 this.listeners = [];
6059 Roo.util.Event.prototype = {
6060 addListener : function(fn, scope, options){
6061 var o = options || {};
6062 scope = scope || this.obj;
6063 if(!this.isListening(fn, scope)){
6064 var l = {fn: fn, scope: scope, options: o};
6067 h = createDelayed(h, o, scope);
6070 h = createSingle(h, this, fn, scope);
6073 h = createBuffered(h, o, scope);
6076 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6077 this.listeners.push(l);
6079 this.listeners = this.listeners.slice(0);
6080 this.listeners.push(l);
6085 findListener : function(fn, scope){
6086 scope = scope || this.obj;
6087 var ls = this.listeners;
6088 for(var i = 0, len = ls.length; i < len; i++){
6090 if(l.fn == fn && l.scope == scope){
6097 isListening : function(fn, scope){
6098 return this.findListener(fn, scope) != -1;
6101 removeListener : function(fn, scope){
6103 if((index = this.findListener(fn, scope)) != -1){
6105 this.listeners.splice(index, 1);
6107 this.listeners = this.listeners.slice(0);
6108 this.listeners.splice(index, 1);
6115 clearListeners : function(){
6116 this.listeners = [];
6120 var ls = this.listeners, scope, len = ls.length;
6123 var args = Array.prototype.slice.call(arguments, 0);
6124 for(var i = 0; i < len; i++){
6126 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6127 this.firing = false;
6131 this.firing = false;
6138 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6145 * @class Roo.Document
6146 * @extends Roo.util.Observable
6147 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6149 * @param {Object} config the methods and properties of the 'base' class for the application.
6151 * Generic Page handler - implement this to start your app..
6154 * MyProject = new Roo.Document({
6156 'load' : true // your events..
6159 'ready' : function() {
6160 // fired on Roo.onReady()
6165 Roo.Document = function(cfg) {
6170 Roo.util.Observable.call(this,cfg);
6174 Roo.onReady(function() {
6175 _this.fireEvent('ready');
6181 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6183 * Ext JS Library 1.1.1
6184 * Copyright(c) 2006-2007, Ext JS, LLC.
6186 * Originally Released Under LGPL - original licence link has changed is not relivant.
6189 * <script type="text/javascript">
6193 * @class Roo.EventManager
6194 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6195 * several useful events directly.
6196 * See {@link Roo.EventObject} for more details on normalized event objects.
6199 Roo.EventManager = function(){
6200 var docReadyEvent, docReadyProcId, docReadyState = false;
6201 var resizeEvent, resizeTask, textEvent, textSize;
6202 var E = Roo.lib.Event;
6203 var D = Roo.lib.Dom;
6208 var fireDocReady = function(){
6210 docReadyState = true;
6213 clearInterval(docReadyProcId);
6215 if(Roo.isGecko || Roo.isOpera) {
6216 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6219 var defer = document.getElementById("ie-deferred-loader");
6221 defer.onreadystatechange = null;
6222 defer.parentNode.removeChild(defer);
6226 docReadyEvent.fire();
6227 docReadyEvent.clearListeners();
6232 var initDocReady = function(){
6233 docReadyEvent = new Roo.util.Event();
6234 if(Roo.isGecko || Roo.isOpera) {
6235 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6237 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6238 var defer = document.getElementById("ie-deferred-loader");
6239 defer.onreadystatechange = function(){
6240 if(this.readyState == "complete"){
6244 }else if(Roo.isSafari){
6245 docReadyProcId = setInterval(function(){
6246 var rs = document.readyState;
6247 if(rs == "complete") {
6252 // no matter what, make sure it fires on load
6253 E.on(window, "load", fireDocReady);
6256 var createBuffered = function(h, o){
6257 var task = new Roo.util.DelayedTask(h);
6259 // create new event object impl so new events don't wipe out properties
6260 e = new Roo.EventObjectImpl(e);
6261 task.delay(o.buffer, h, null, [e]);
6265 var createSingle = function(h, el, ename, fn){
6267 Roo.EventManager.removeListener(el, ename, fn);
6272 var createDelayed = function(h, o){
6274 // create new event object impl so new events don't wipe out properties
6275 e = new Roo.EventObjectImpl(e);
6276 setTimeout(function(){
6281 var transitionEndVal = false;
6283 var transitionEnd = function()
6285 if (transitionEndVal) {
6286 return transitionEndVal;
6288 var el = document.createElement('div');
6290 var transEndEventNames = {
6291 WebkitTransition : 'webkitTransitionEnd',
6292 MozTransition : 'transitionend',
6293 OTransition : 'oTransitionEnd otransitionend',
6294 transition : 'transitionend'
6297 for (var name in transEndEventNames) {
6298 if (el.style[name] !== undefined) {
6299 transitionEndVal = transEndEventNames[name];
6300 return transitionEndVal ;
6307 var listen = function(element, ename, opt, fn, scope){
6308 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6309 fn = fn || o.fn; scope = scope || o.scope;
6310 var el = Roo.getDom(element);
6314 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6317 if (ename == 'transitionend') {
6318 ename = transitionEnd();
6320 var h = function(e){
6321 e = Roo.EventObject.setEvent(e);
6324 t = e.getTarget(o.delegate, el);
6331 if(o.stopEvent === true){
6334 if(o.preventDefault === true){
6337 if(o.stopPropagation === true){
6338 e.stopPropagation();
6341 if(o.normalized === false){
6345 fn.call(scope || el, e, t, o);
6348 h = createDelayed(h, o);
6351 h = createSingle(h, el, ename, fn);
6354 h = createBuffered(h, o);
6357 fn._handlers = fn._handlers || [];
6360 fn._handlers.push([Roo.id(el), ename, h]);
6365 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6366 el.addEventListener("DOMMouseScroll", h, false);
6367 E.on(window, 'unload', function(){
6368 el.removeEventListener("DOMMouseScroll", h, false);
6371 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6372 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6377 var stopListening = function(el, ename, fn){
6378 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6380 for(var i = 0, len = hds.length; i < len; i++){
6382 if(h[0] == id && h[1] == ename){
6389 E.un(el, ename, hd);
6390 el = Roo.getDom(el);
6391 if(ename == "mousewheel" && el.addEventListener){
6392 el.removeEventListener("DOMMouseScroll", hd, false);
6394 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6395 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6399 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6406 * @scope Roo.EventManager
6411 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6412 * object with a Roo.EventObject
6413 * @param {Function} fn The method the event invokes
6414 * @param {Object} scope An object that becomes the scope of the handler
6415 * @param {boolean} override If true, the obj passed in becomes
6416 * the execution scope of the listener
6417 * @return {Function} The wrapped function
6420 wrap : function(fn, scope, override){
6422 Roo.EventObject.setEvent(e);
6423 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6428 * Appends an event handler to an element (shorthand for addListener)
6429 * @param {String/HTMLElement} element The html element or id to assign the
6430 * @param {String} eventName The type of event to listen for
6431 * @param {Function} handler The method the event invokes
6432 * @param {Object} scope (optional) The scope in which to execute the handler
6433 * function. The handler function's "this" context.
6434 * @param {Object} options (optional) An object containing handler configuration
6435 * properties. This may contain any of the following properties:<ul>
6436 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6437 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6438 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6439 * <li>preventDefault {Boolean} True to prevent the default action</li>
6440 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6441 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6442 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6443 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6444 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6445 * by the specified number of milliseconds. If the event fires again within that time, the original
6446 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6449 * <b>Combining Options</b><br>
6450 * Using the options argument, it is possible to combine different types of listeners:<br>
6452 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6454 el.on('click', this.onClick, this, {
6461 * <b>Attaching multiple handlers in 1 call</b><br>
6462 * The method also allows for a single argument to be passed which is a config object containing properties
6463 * which specify multiple handlers.
6473 fn: this.onMouseOver
6482 * Or a shorthand syntax:<br>
6485 'click' : this.onClick,
6486 'mouseover' : this.onMouseOver,
6487 'mouseout' : this.onMouseOut
6491 addListener : function(element, eventName, fn, scope, options){
6492 if(typeof eventName == "object"){
6498 if(typeof o[e] == "function"){
6500 listen(element, e, o, o[e], o.scope);
6502 // individual options
6503 listen(element, e, o[e]);
6508 return listen(element, eventName, options, fn, scope);
6512 * Removes an event handler
6514 * @param {String/HTMLElement} element The id or html element to remove the
6516 * @param {String} eventName The type of event
6517 * @param {Function} fn
6518 * @return {Boolean} True if a listener was actually removed
6520 removeListener : function(element, eventName, fn){
6521 return stopListening(element, eventName, fn);
6525 * Fires when the document is ready (before onload and before images are loaded). Can be
6526 * accessed shorthanded Roo.onReady().
6527 * @param {Function} fn The method the event invokes
6528 * @param {Object} scope An object that becomes the scope of the handler
6529 * @param {boolean} options
6531 onDocumentReady : function(fn, scope, options){
6532 if(docReadyState){ // if it already fired
6533 docReadyEvent.addListener(fn, scope, options);
6534 docReadyEvent.fire();
6535 docReadyEvent.clearListeners();
6541 docReadyEvent.addListener(fn, scope, options);
6545 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6546 * @param {Function} fn The method the event invokes
6547 * @param {Object} scope An object that becomes the scope of the handler
6548 * @param {boolean} options
6550 onWindowResize : function(fn, scope, options){
6552 resizeEvent = new Roo.util.Event();
6553 resizeTask = new Roo.util.DelayedTask(function(){
6554 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6556 E.on(window, "resize", function(){
6558 resizeTask.delay(50);
6560 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6564 resizeEvent.addListener(fn, scope, options);
6568 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6569 * @param {Function} fn The method the event invokes
6570 * @param {Object} scope An object that becomes the scope of the handler
6571 * @param {boolean} options
6573 onTextResize : function(fn, scope, options){
6575 textEvent = new Roo.util.Event();
6576 var textEl = new Roo.Element(document.createElement('div'));
6577 textEl.dom.className = 'x-text-resize';
6578 textEl.dom.innerHTML = 'X';
6579 textEl.appendTo(document.body);
6580 textSize = textEl.dom.offsetHeight;
6581 setInterval(function(){
6582 if(textEl.dom.offsetHeight != textSize){
6583 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6585 }, this.textResizeInterval);
6587 textEvent.addListener(fn, scope, options);
6591 * Removes the passed window resize listener.
6592 * @param {Function} fn The method the event invokes
6593 * @param {Object} scope The scope of handler
6595 removeResizeListener : function(fn, scope){
6597 resizeEvent.removeListener(fn, scope);
6602 fireResize : function(){
6604 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6608 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6612 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6614 textResizeInterval : 50
6619 * @scopeAlias pub=Roo.EventManager
6623 * Appends an event handler to an element (shorthand for addListener)
6624 * @param {String/HTMLElement} element The html element or id to assign the
6625 * @param {String} eventName The type of event to listen for
6626 * @param {Function} handler The method the event invokes
6627 * @param {Object} scope (optional) The scope in which to execute the handler
6628 * function. The handler function's "this" context.
6629 * @param {Object} options (optional) An object containing handler configuration
6630 * properties. This may contain any of the following properties:<ul>
6631 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6632 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6633 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6634 * <li>preventDefault {Boolean} True to prevent the default action</li>
6635 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6636 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6637 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6638 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6639 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6640 * by the specified number of milliseconds. If the event fires again within that time, the original
6641 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6644 * <b>Combining Options</b><br>
6645 * Using the options argument, it is possible to combine different types of listeners:<br>
6647 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6649 el.on('click', this.onClick, this, {
6656 * <b>Attaching multiple handlers in 1 call</b><br>
6657 * The method also allows for a single argument to be passed which is a config object containing properties
6658 * which specify multiple handlers.
6668 fn: this.onMouseOver
6677 * Or a shorthand syntax:<br>
6680 'click' : this.onClick,
6681 'mouseover' : this.onMouseOver,
6682 'mouseout' : this.onMouseOut
6686 pub.on = pub.addListener;
6687 pub.un = pub.removeListener;
6689 pub.stoppedMouseDownEvent = new Roo.util.Event();
6693 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6694 * @param {Function} fn The method the event invokes
6695 * @param {Object} scope An object that becomes the scope of the handler
6696 * @param {boolean} override If true, the obj passed in becomes
6697 * the execution scope of the listener
6701 Roo.onReady = Roo.EventManager.onDocumentReady;
6703 Roo.onReady(function(){
6704 var bd = Roo.get(document.body);
6709 : Roo.isIE11 ? "roo-ie11"
6710 : Roo.isEdge ? "roo-edge"
6711 : Roo.isGecko ? "roo-gecko"
6712 : Roo.isOpera ? "roo-opera"
6713 : Roo.isSafari ? "roo-safari" : ""];
6716 cls.push("roo-mac");
6719 cls.push("roo-linux");
6722 cls.push("roo-ios");
6725 cls.push("roo-touch");
6727 if(Roo.isBorderBox){
6728 cls.push('roo-border-box');
6730 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6731 var p = bd.dom.parentNode;
6733 p.className += ' roo-strict';
6736 bd.addClass(cls.join(' '));
6740 * @class Roo.EventObject
6741 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6742 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6745 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6747 var target = e.getTarget();
6750 var myDiv = Roo.get("myDiv");
6751 myDiv.on("click", handleClick);
6753 Roo.EventManager.on("myDiv", 'click', handleClick);
6754 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6758 Roo.EventObject = function(){
6760 var E = Roo.lib.Event;
6762 // safari keypress events for special keys return bad keycodes
6765 63235 : 39, // right
6768 63276 : 33, // page up
6769 63277 : 34, // page down
6770 63272 : 46, // delete
6775 // normalize button clicks
6776 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6777 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6779 Roo.EventObjectImpl = function(e){
6781 this.setEvent(e.browserEvent || e);
6784 Roo.EventObjectImpl.prototype = {
6786 * Used to fix doc tools.
6787 * @scope Roo.EventObject.prototype
6793 /** The normal browser event */
6794 browserEvent : null,
6795 /** The button pressed in a mouse event */
6797 /** True if the shift key was down during the event */
6799 /** True if the control key was down during the event */
6801 /** True if the alt key was down during the event */
6860 setEvent : function(e){
6861 if(e == this || (e && e.browserEvent)){ // already wrapped
6864 this.browserEvent = e;
6866 // normalize buttons
6867 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6868 if(e.type == 'click' && this.button == -1){
6872 this.shiftKey = e.shiftKey;
6873 // mac metaKey behaves like ctrlKey
6874 this.ctrlKey = e.ctrlKey || e.metaKey;
6875 this.altKey = e.altKey;
6876 // in getKey these will be normalized for the mac
6877 this.keyCode = e.keyCode;
6878 // keyup warnings on firefox.
6879 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6880 // cache the target for the delayed and or buffered events
6881 this.target = E.getTarget(e);
6883 this.xy = E.getXY(e);
6886 this.shiftKey = false;
6887 this.ctrlKey = false;
6888 this.altKey = false;
6898 * Stop the event (preventDefault and stopPropagation)
6900 stopEvent : function(){
6901 if(this.browserEvent){
6902 if(this.browserEvent.type == 'mousedown'){
6903 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6905 E.stopEvent(this.browserEvent);
6910 * Prevents the browsers default handling of the event.
6912 preventDefault : function(){
6913 if(this.browserEvent){
6914 E.preventDefault(this.browserEvent);
6919 isNavKeyPress : function(){
6920 var k = this.keyCode;
6921 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6922 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6925 isSpecialKey : function(){
6926 var k = this.keyCode;
6927 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6928 (k == 16) || (k == 17) ||
6929 (k >= 18 && k <= 20) ||
6930 (k >= 33 && k <= 35) ||
6931 (k >= 36 && k <= 39) ||
6932 (k >= 44 && k <= 45);
6935 * Cancels bubbling of the event.
6937 stopPropagation : function(){
6938 if(this.browserEvent){
6939 if(this.type == 'mousedown'){
6940 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6942 E.stopPropagation(this.browserEvent);
6947 * Gets the key code for the event.
6950 getCharCode : function(){
6951 return this.charCode || this.keyCode;
6955 * Returns a normalized keyCode for the event.
6956 * @return {Number} The key code
6958 getKey : function(){
6959 var k = this.keyCode || this.charCode;
6960 return Roo.isSafari ? (safariKeys[k] || k) : k;
6964 * Gets the x coordinate of the event.
6967 getPageX : function(){
6972 * Gets the y coordinate of the event.
6975 getPageY : function(){
6980 * Gets the time of the event.
6983 getTime : function(){
6984 if(this.browserEvent){
6985 return E.getTime(this.browserEvent);
6991 * Gets the page coordinates of the event.
6992 * @return {Array} The xy values like [x, y]
6999 * Gets the target for the event.
7000 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7001 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7002 search as a number or element (defaults to 10 || document.body)
7003 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7004 * @return {HTMLelement}
7006 getTarget : function(selector, maxDepth, returnEl){
7007 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7010 * Gets the related target.
7011 * @return {HTMLElement}
7013 getRelatedTarget : function(){
7014 if(this.browserEvent){
7015 return E.getRelatedTarget(this.browserEvent);
7021 * Normalizes mouse wheel delta across browsers
7022 * @return {Number} The delta
7024 getWheelDelta : function(){
7025 var e = this.browserEvent;
7027 if(e.wheelDelta){ /* IE/Opera. */
7028 delta = e.wheelDelta/120;
7029 }else if(e.detail){ /* Mozilla case. */
7030 delta = -e.detail/3;
7036 * Returns true if the control, meta, shift or alt key was pressed during this event.
7039 hasModifier : function(){
7040 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7044 * Returns true if the target of this event equals el or is a child of el
7045 * @param {String/HTMLElement/Element} el
7046 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7049 within : function(el, related){
7050 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7051 return t && Roo.fly(el).contains(t);
7054 getPoint : function(){
7055 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7059 return new Roo.EventObjectImpl();
7064 * Ext JS Library 1.1.1
7065 * Copyright(c) 2006-2007, Ext JS, LLC.
7067 * Originally Released Under LGPL - original licence link has changed is not relivant.
7070 * <script type="text/javascript">
7074 // was in Composite Element!??!?!
7077 var D = Roo.lib.Dom;
7078 var E = Roo.lib.Event;
7079 var A = Roo.lib.Anim;
7081 // local style camelizing for speed
7083 var camelRe = /(-[a-z])/gi;
7084 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7085 var view = document.defaultView;
7088 * @class Roo.Element
7089 * Represents an Element in the DOM.<br><br>
7092 var el = Roo.get("my-div");
7095 var el = getEl("my-div");
7097 // or with a DOM element
7098 var el = Roo.get(myDivElement);
7100 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7101 * each call instead of constructing a new one.<br><br>
7102 * <b>Animations</b><br />
7103 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7104 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7106 Option Default Description
7107 --------- -------- ---------------------------------------------
7108 duration .35 The duration of the animation in seconds
7109 easing easeOut The YUI easing method
7110 callback none A function to execute when the anim completes
7111 scope this The scope (this) of the callback function
7113 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7114 * manipulate the animation. Here's an example:
7116 var el = Roo.get("my-div");
7121 // default animation
7122 el.setWidth(100, true);
7124 // animation with some options set
7131 // using the "anim" property to get the Anim object
7137 el.setWidth(100, opt);
7139 if(opt.anim.isAnimated()){
7143 * <b> Composite (Collections of) Elements</b><br />
7144 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7145 * @constructor Create a new Element directly.
7146 * @param {String/HTMLElement} element
7147 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7149 Roo.Element = function(element, forceNew){
7150 var dom = typeof element == "string" ?
7151 document.getElementById(element) : element;
7152 if(!dom){ // invalid id/element
7156 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7157 return Roo.Element.cache[id];
7167 * The DOM element ID
7170 this.id = id || Roo.id(dom);
7173 var El = Roo.Element;
7177 * The element's default display mode (defaults to "")
7180 originalDisplay : "",
7183 // note this is overridden in BS version..
7186 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7192 * Sets the element's visibility mode. When setVisible() is called it
7193 * will use this to determine whether to set the visibility or the display property.
7194 * @param visMode Element.VISIBILITY or Element.DISPLAY
7195 * @return {Roo.Element} this
7197 setVisibilityMode : function(visMode){
7198 this.visibilityMode = visMode;
7202 * Convenience method for setVisibilityMode(Element.DISPLAY)
7203 * @param {String} display (optional) What to set display to when visible
7204 * @return {Roo.Element} this
7206 enableDisplayMode : function(display){
7207 this.setVisibilityMode(El.DISPLAY);
7208 if(typeof display != "undefined") { this.originalDisplay = display; }
7213 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7214 * @param {String} selector The simple selector to test
7215 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7216 search as a number or element (defaults to 10 || document.body)
7217 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7218 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7220 findParent : function(simpleSelector, maxDepth, returnEl){
7221 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7222 maxDepth = maxDepth || 50;
7223 if(typeof maxDepth != "number"){
7224 stopEl = Roo.getDom(maxDepth);
7227 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7228 if(dq.is(p, simpleSelector)){
7229 return returnEl ? Roo.get(p) : p;
7239 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7240 * @param {String} selector The simple selector to test
7241 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7242 search as a number or element (defaults to 10 || document.body)
7243 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7244 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7246 findParentNode : function(simpleSelector, maxDepth, returnEl){
7247 var p = Roo.fly(this.dom.parentNode, '_internal');
7248 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7252 * Looks at the scrollable parent element
7254 findScrollableParent : function()
7256 var overflowRegex = /(auto|scroll)/;
7258 if(this.getStyle('position') === 'fixed'){
7259 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7262 var excludeStaticParent = this.getStyle('position') === "absolute";
7264 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7266 if (excludeStaticParent && parent.getStyle('position') === "static") {
7270 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7274 if(parent.dom.nodeName.toLowerCase() == 'body'){
7275 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7279 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7283 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7284 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7285 * @param {String} selector The simple selector to test
7286 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7287 search as a number or element (defaults to 10 || document.body)
7288 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7290 up : function(simpleSelector, maxDepth){
7291 return this.findParentNode(simpleSelector, maxDepth, true);
7297 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7298 * @param {String} selector The simple selector to test
7299 * @return {Boolean} True if this element matches the selector, else false
7301 is : function(simpleSelector){
7302 return Roo.DomQuery.is(this.dom, simpleSelector);
7306 * Perform animation on this element.
7307 * @param {Object} args The YUI animation control args
7308 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7309 * @param {Function} onComplete (optional) Function to call when animation completes
7310 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7311 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7312 * @return {Roo.Element} this
7314 animate : function(args, duration, onComplete, easing, animType){
7315 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7320 * @private Internal animation call
7322 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7323 animType = animType || 'run';
7325 var anim = Roo.lib.Anim[animType](
7327 (opt.duration || defaultDur) || .35,
7328 (opt.easing || defaultEase) || 'easeOut',
7330 Roo.callback(cb, this);
7331 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7339 // private legacy anim prep
7340 preanim : function(a, i){
7341 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7345 * Removes worthless text nodes
7346 * @param {Boolean} forceReclean (optional) By default the element
7347 * keeps track if it has been cleaned already so
7348 * you can call this over and over. However, if you update the element and
7349 * need to force a reclean, you can pass true.
7351 clean : function(forceReclean){
7352 if(this.isCleaned && forceReclean !== true){
7356 var d = this.dom, n = d.firstChild, ni = -1;
7358 var nx = n.nextSibling;
7359 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7366 this.isCleaned = true;
7371 calcOffsetsTo : function(el){
7374 var restorePos = false;
7375 if(el.getStyle('position') == 'static'){
7376 el.position('relative');
7381 while(op && op != d && op.tagName != 'HTML'){
7384 op = op.offsetParent;
7387 el.position('static');
7393 * Scrolls this element into view within the passed container.
7394 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7395 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7396 * @return {Roo.Element} this
7398 scrollIntoView : function(container, hscroll){
7399 var c = Roo.getDom(container) || document.body;
7402 var o = this.calcOffsetsTo(c),
7405 b = t+el.offsetHeight,
7406 r = l+el.offsetWidth;
7408 var ch = c.clientHeight;
7409 var ct = parseInt(c.scrollTop, 10);
7410 var cl = parseInt(c.scrollLeft, 10);
7412 var cr = cl + c.clientWidth;
7420 if(hscroll !== false){
7424 c.scrollLeft = r-c.clientWidth;
7431 scrollChildIntoView : function(child, hscroll){
7432 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7436 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7437 * the new height may not be available immediately.
7438 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7439 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7440 * @param {Function} onComplete (optional) Function to call when animation completes
7441 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7442 * @return {Roo.Element} this
7444 autoHeight : function(animate, duration, onComplete, easing){
7445 var oldHeight = this.getHeight();
7447 this.setHeight(1); // force clipping
7448 setTimeout(function(){
7449 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7451 this.setHeight(height);
7453 if(typeof onComplete == "function"){
7457 this.setHeight(oldHeight); // restore original height
7458 this.setHeight(height, animate, duration, function(){
7460 if(typeof onComplete == "function") { onComplete(); }
7461 }.createDelegate(this), easing);
7463 }.createDelegate(this), 0);
7468 * Returns true if this element is an ancestor of the passed element
7469 * @param {HTMLElement/String} el The element to check
7470 * @return {Boolean} True if this element is an ancestor of el, else false
7472 contains : function(el){
7473 if(!el){return false;}
7474 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7478 * Checks whether the element is currently visible using both visibility and display properties.
7479 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7480 * @return {Boolean} True if the element is currently visible, else false
7482 isVisible : function(deep) {
7483 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7484 if(deep !== true || !vis){
7487 var p = this.dom.parentNode;
7488 while(p && p.tagName.toLowerCase() != "body"){
7489 if(!Roo.fly(p, '_isVisible').isVisible()){
7498 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7499 * @param {String} selector The CSS selector
7500 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7501 * @return {CompositeElement/CompositeElementLite} The composite element
7503 select : function(selector, unique){
7504 return El.select(selector, unique, this.dom);
7508 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7509 * @param {String} selector The CSS selector
7510 * @return {Array} An array of the matched nodes
7512 query : function(selector, unique){
7513 return Roo.DomQuery.select(selector, this.dom);
7517 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7518 * @param {String} selector The CSS selector
7519 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7520 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7522 child : function(selector, returnDom){
7523 var n = Roo.DomQuery.selectNode(selector, this.dom);
7524 return returnDom ? n : Roo.get(n);
7528 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7529 * @param {String} selector The CSS selector
7530 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7531 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7533 down : function(selector, returnDom){
7534 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7535 return returnDom ? n : Roo.get(n);
7539 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7540 * @param {String} group The group the DD object is member of
7541 * @param {Object} config The DD config object
7542 * @param {Object} overrides An object containing methods to override/implement on the DD object
7543 * @return {Roo.dd.DD} The DD object
7545 initDD : function(group, config, overrides){
7546 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7547 return Roo.apply(dd, overrides);
7551 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7552 * @param {String} group The group the DDProxy object is member of
7553 * @param {Object} config The DDProxy config object
7554 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7555 * @return {Roo.dd.DDProxy} The DDProxy object
7557 initDDProxy : function(group, config, overrides){
7558 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7559 return Roo.apply(dd, overrides);
7563 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7564 * @param {String} group The group the DDTarget object is member of
7565 * @param {Object} config The DDTarget config object
7566 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7567 * @return {Roo.dd.DDTarget} The DDTarget object
7569 initDDTarget : function(group, config, overrides){
7570 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7571 return Roo.apply(dd, overrides);
7575 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7576 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7577 * @param {Boolean} visible Whether the element is visible
7578 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7579 * @return {Roo.Element} this
7581 setVisible : function(visible, animate){
7583 if(this.visibilityMode == El.DISPLAY){
7584 this.setDisplayed(visible);
7587 this.dom.style.visibility = visible ? "visible" : "hidden";
7590 // closure for composites
7592 var visMode = this.visibilityMode;
7594 this.setOpacity(.01);
7595 this.setVisible(true);
7597 this.anim({opacity: { to: (visible?1:0) }},
7598 this.preanim(arguments, 1),
7599 null, .35, 'easeIn', function(){
7601 if(visMode == El.DISPLAY){
7602 dom.style.display = "none";
7604 dom.style.visibility = "hidden";
7606 Roo.get(dom).setOpacity(1);
7614 * Returns true if display is not "none"
7617 isDisplayed : function() {
7618 return this.getStyle("display") != "none";
7622 * Toggles the element's visibility or display, depending on visibility mode.
7623 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7624 * @return {Roo.Element} this
7626 toggle : function(animate){
7627 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7632 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7633 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7634 * @return {Roo.Element} this
7636 setDisplayed : function(value) {
7637 if(typeof value == "boolean"){
7638 value = value ? this.originalDisplay : "none";
7640 this.setStyle("display", value);
7645 * Tries to focus the element. Any exceptions are caught and ignored.
7646 * @return {Roo.Element} this
7648 focus : function() {
7656 * Tries to blur the element. Any exceptions are caught and ignored.
7657 * @return {Roo.Element} this
7667 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7668 * @param {String/Array} className The CSS class to add, or an array of classes
7669 * @return {Roo.Element} this
7671 addClass : function(className){
7672 if(className instanceof Array){
7673 for(var i = 0, len = className.length; i < len; i++) {
7674 this.addClass(className[i]);
7677 if(className && !this.hasClass(className)){
7678 this.dom.className = this.dom.className + " " + className;
7685 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7686 * @param {String/Array} className The CSS class to add, or an array of classes
7687 * @return {Roo.Element} this
7689 radioClass : function(className){
7690 var siblings = this.dom.parentNode.childNodes;
7691 for(var i = 0; i < siblings.length; i++) {
7692 var s = siblings[i];
7693 if(s.nodeType == 1){
7694 Roo.get(s).removeClass(className);
7697 this.addClass(className);
7702 * Removes one or more CSS classes from the element.
7703 * @param {String/Array} className The CSS class to remove, or an array of classes
7704 * @return {Roo.Element} this
7706 removeClass : function(className){
7707 if(!className || !this.dom.className){
7710 if(className instanceof Array){
7711 for(var i = 0, len = className.length; i < len; i++) {
7712 this.removeClass(className[i]);
7715 if(this.hasClass(className)){
7716 var re = this.classReCache[className];
7718 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7719 this.classReCache[className] = re;
7721 this.dom.className =
7722 this.dom.className.replace(re, " ");
7732 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7733 * @param {String} className The CSS class to toggle
7734 * @return {Roo.Element} this
7736 toggleClass : function(className){
7737 if(this.hasClass(className)){
7738 this.removeClass(className);
7740 this.addClass(className);
7746 * Checks if the specified CSS class exists on this element's DOM node.
7747 * @param {String} className The CSS class to check for
7748 * @return {Boolean} True if the class exists, else false
7750 hasClass : function(className){
7751 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7755 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7756 * @param {String} oldClassName The CSS class to replace
7757 * @param {String} newClassName The replacement CSS class
7758 * @return {Roo.Element} this
7760 replaceClass : function(oldClassName, newClassName){
7761 this.removeClass(oldClassName);
7762 this.addClass(newClassName);
7767 * Returns an object with properties matching the styles requested.
7768 * For example, el.getStyles('color', 'font-size', 'width') might return
7769 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7770 * @param {String} style1 A style name
7771 * @param {String} style2 A style name
7772 * @param {String} etc.
7773 * @return {Object} The style object
7775 getStyles : function(){
7776 var a = arguments, len = a.length, r = {};
7777 for(var i = 0; i < len; i++){
7778 r[a[i]] = this.getStyle(a[i]);
7784 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7785 * @param {String} property The style property whose value is returned.
7786 * @return {String} The current value of the style property for this element.
7788 getStyle : function(){
7789 return view && view.getComputedStyle ?
7791 var el = this.dom, v, cs, camel;
7792 if(prop == 'float'){
7795 if(el.style && (v = el.style[prop])){
7798 if(cs = view.getComputedStyle(el, "")){
7799 if(!(camel = propCache[prop])){
7800 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7807 var el = this.dom, v, cs, camel;
7808 if(prop == 'opacity'){
7809 if(typeof el.style.filter == 'string'){
7810 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7812 var fv = parseFloat(m[1]);
7814 return fv ? fv / 100 : 0;
7819 }else if(prop == 'float'){
7820 prop = "styleFloat";
7822 if(!(camel = propCache[prop])){
7823 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7825 if(v = el.style[camel]){
7828 if(cs = el.currentStyle){
7836 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7837 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7838 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7839 * @return {Roo.Element} this
7841 setStyle : function(prop, value){
7842 if(typeof prop == "string"){
7844 if (prop == 'float') {
7845 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7850 if(!(camel = propCache[prop])){
7851 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7854 if(camel == 'opacity') {
7855 this.setOpacity(value);
7857 this.dom.style[camel] = value;
7860 for(var style in prop){
7861 if(typeof prop[style] != "function"){
7862 this.setStyle(style, prop[style]);
7870 * More flexible version of {@link #setStyle} for setting style properties.
7871 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7872 * a function which returns such a specification.
7873 * @return {Roo.Element} this
7875 applyStyles : function(style){
7876 Roo.DomHelper.applyStyles(this.dom, style);
7881 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7882 * @return {Number} The X position of the element
7885 return D.getX(this.dom);
7889 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7890 * @return {Number} The Y position of the element
7893 return D.getY(this.dom);
7897 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7898 * @return {Array} The XY position of the element
7901 return D.getXY(this.dom);
7905 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7906 * @param {Number} The X position of the element
7907 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7908 * @return {Roo.Element} this
7910 setX : function(x, animate){
7912 D.setX(this.dom, x);
7914 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7920 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7921 * @param {Number} The Y position of the element
7922 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7923 * @return {Roo.Element} this
7925 setY : function(y, animate){
7927 D.setY(this.dom, y);
7929 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7935 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7936 * @param {String} left The left CSS property value
7937 * @return {Roo.Element} this
7939 setLeft : function(left){
7940 this.setStyle("left", this.addUnits(left));
7945 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7946 * @param {String} top The top CSS property value
7947 * @return {Roo.Element} this
7949 setTop : function(top){
7950 this.setStyle("top", this.addUnits(top));
7955 * Sets the element's CSS right style.
7956 * @param {String} right The right CSS property value
7957 * @return {Roo.Element} this
7959 setRight : function(right){
7960 this.setStyle("right", this.addUnits(right));
7965 * Sets the element's CSS bottom style.
7966 * @param {String} bottom The bottom CSS property value
7967 * @return {Roo.Element} this
7969 setBottom : function(bottom){
7970 this.setStyle("bottom", this.addUnits(bottom));
7975 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7976 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7977 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7978 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7979 * @return {Roo.Element} this
7981 setXY : function(pos, animate){
7983 D.setXY(this.dom, pos);
7985 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7991 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7992 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7993 * @param {Number} x X value for new position (coordinates are page-based)
7994 * @param {Number} y Y value for new position (coordinates are page-based)
7995 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7996 * @return {Roo.Element} this
7998 setLocation : function(x, y, animate){
7999 this.setXY([x, y], this.preanim(arguments, 2));
8004 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8005 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8006 * @param {Number} x X value for new position (coordinates are page-based)
8007 * @param {Number} y Y value for new position (coordinates are page-based)
8008 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8009 * @return {Roo.Element} this
8011 moveTo : function(x, y, animate){
8012 this.setXY([x, y], this.preanim(arguments, 2));
8017 * Returns the region of the given element.
8018 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8019 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8021 getRegion : function(){
8022 return D.getRegion(this.dom);
8026 * Returns the offset height of the element
8027 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8028 * @return {Number} The element's height
8030 getHeight : function(contentHeight){
8031 var h = this.dom.offsetHeight || 0;
8032 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8036 * Returns the offset width of the element
8037 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8038 * @return {Number} The element's width
8040 getWidth : function(contentWidth){
8041 var w = this.dom.offsetWidth || 0;
8042 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8046 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8047 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8048 * if a height has not been set using CSS.
8051 getComputedHeight : function(){
8052 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8054 h = parseInt(this.getStyle('height'), 10) || 0;
8055 if(!this.isBorderBox()){
8056 h += this.getFrameWidth('tb');
8063 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8064 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8065 * if a width has not been set using CSS.
8068 getComputedWidth : function(){
8069 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8071 w = parseInt(this.getStyle('width'), 10) || 0;
8072 if(!this.isBorderBox()){
8073 w += this.getFrameWidth('lr');
8080 * Returns the size of the element.
8081 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8082 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8084 getSize : function(contentSize){
8085 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8089 * Returns the width and height of the viewport.
8090 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8092 getViewSize : function(){
8093 var d = this.dom, doc = document, aw = 0, ah = 0;
8094 if(d == doc || d == doc.body){
8095 return {width : D.getViewWidth(), height: D.getViewHeight()};
8098 width : d.clientWidth,
8099 height: d.clientHeight
8105 * Returns the value of the "value" attribute
8106 * @param {Boolean} asNumber true to parse the value as a number
8107 * @return {String/Number}
8109 getValue : function(asNumber){
8110 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8114 adjustWidth : function(width){
8115 if(typeof width == "number"){
8116 if(this.autoBoxAdjust && !this.isBorderBox()){
8117 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8127 adjustHeight : function(height){
8128 if(typeof height == "number"){
8129 if(this.autoBoxAdjust && !this.isBorderBox()){
8130 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8140 * Set the width of the element
8141 * @param {Number} width The new width
8142 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8143 * @return {Roo.Element} this
8145 setWidth : function(width, animate){
8146 width = this.adjustWidth(width);
8148 this.dom.style.width = this.addUnits(width);
8150 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8156 * Set the height of the element
8157 * @param {Number} height The new height
8158 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8159 * @return {Roo.Element} this
8161 setHeight : function(height, animate){
8162 height = this.adjustHeight(height);
8164 this.dom.style.height = this.addUnits(height);
8166 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8172 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8173 * @param {Number} width The new width
8174 * @param {Number} height The new height
8175 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8176 * @return {Roo.Element} this
8178 setSize : function(width, height, animate){
8179 if(typeof width == "object"){ // in case of object from getSize()
8180 height = width.height; width = width.width;
8182 width = this.adjustWidth(width); height = this.adjustHeight(height);
8184 this.dom.style.width = this.addUnits(width);
8185 this.dom.style.height = this.addUnits(height);
8187 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8193 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8194 * @param {Number} x X value for new position (coordinates are page-based)
8195 * @param {Number} y Y value for new position (coordinates are page-based)
8196 * @param {Number} width The new width
8197 * @param {Number} height The new height
8198 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8199 * @return {Roo.Element} this
8201 setBounds : function(x, y, width, height, animate){
8203 this.setSize(width, height);
8204 this.setLocation(x, y);
8206 width = this.adjustWidth(width); height = this.adjustHeight(height);
8207 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8208 this.preanim(arguments, 4), 'motion');
8214 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
8215 * @param {Roo.lib.Region} region The region to fill
8216 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8217 * @return {Roo.Element} this
8219 setRegion : function(region, animate){
8220 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8225 * Appends an event handler
8227 * @param {String} eventName The type of event to append
8228 * @param {Function} fn The method the event invokes
8229 * @param {Object} scope (optional) The scope (this object) of the fn
8230 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8232 addListener : function(eventName, fn, scope, options){
8234 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8236 if (eventName == 'dblclick') {
8237 this.addListener('touchstart', this.onTapHandler, this);
8241 onTapHandler : function(event)
8243 if(!this.tapedTwice) {
8244 this.tapedTwice = true;
8246 setTimeout( function() {
8247 s.tapedTwice = false;
8251 event.preventDefault();
8252 var revent = new MouseEvent('dblclick', {
8258 this.dom.dispatchEvent(revent);
8259 //action on double tap goes below
8264 * Removes an event handler from this element
8265 * @param {String} eventName the type of event to remove
8266 * @param {Function} fn the method the event invokes
8267 * @return {Roo.Element} this
8269 removeListener : function(eventName, fn){
8270 Roo.EventManager.removeListener(this.dom, eventName, fn);
8275 * Removes all previous added listeners from this element
8276 * @return {Roo.Element} this
8278 removeAllListeners : function(){
8279 E.purgeElement(this.dom);
8283 relayEvent : function(eventName, observable){
8284 this.on(eventName, function(e){
8285 observable.fireEvent(eventName, e);
8290 * Set the opacity of the element
8291 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8292 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8293 * @return {Roo.Element} this
8295 setOpacity : function(opacity, animate){
8297 var s = this.dom.style;
8300 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8301 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8303 s.opacity = opacity;
8306 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8312 * Gets the left X coordinate
8313 * @param {Boolean} local True to get the local css position instead of page coordinate
8316 getLeft : function(local){
8320 return parseInt(this.getStyle("left"), 10) || 0;
8325 * Gets the right X coordinate of the element (element X position + element width)
8326 * @param {Boolean} local True to get the local css position instead of page coordinate
8329 getRight : function(local){
8331 return this.getX() + this.getWidth();
8333 return (this.getLeft(true) + this.getWidth()) || 0;
8338 * Gets the top Y coordinate
8339 * @param {Boolean} local True to get the local css position instead of page coordinate
8342 getTop : function(local) {
8346 return parseInt(this.getStyle("top"), 10) || 0;
8351 * Gets the bottom Y coordinate of the element (element Y position + element height)
8352 * @param {Boolean} local True to get the local css position instead of page coordinate
8355 getBottom : function(local){
8357 return this.getY() + this.getHeight();
8359 return (this.getTop(true) + this.getHeight()) || 0;
8364 * Initializes positioning on this element. If a desired position is not passed, it will make the
8365 * the element positioned relative IF it is not already positioned.
8366 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8367 * @param {Number} zIndex (optional) The zIndex to apply
8368 * @param {Number} x (optional) Set the page X position
8369 * @param {Number} y (optional) Set the page Y position
8371 position : function(pos, zIndex, x, y){
8373 if(this.getStyle('position') == 'static'){
8374 this.setStyle('position', 'relative');
8377 this.setStyle("position", pos);
8380 this.setStyle("z-index", zIndex);
8382 if(x !== undefined && y !== undefined){
8384 }else if(x !== undefined){
8386 }else if(y !== undefined){
8392 * Clear positioning back to the default when the document was loaded
8393 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8394 * @return {Roo.Element} this
8396 clearPositioning : function(value){
8404 "position" : "static"
8410 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8411 * snapshot before performing an update and then restoring the element.
8414 getPositioning : function(){
8415 var l = this.getStyle("left");
8416 var t = this.getStyle("top");
8418 "position" : this.getStyle("position"),
8420 "right" : l ? "" : this.getStyle("right"),
8422 "bottom" : t ? "" : this.getStyle("bottom"),
8423 "z-index" : this.getStyle("z-index")
8428 * Gets the width of the border(s) for the specified side(s)
8429 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8430 * passing lr would get the border (l)eft width + the border (r)ight width.
8431 * @return {Number} The width of the sides passed added together
8433 getBorderWidth : function(side){
8434 return this.addStyles(side, El.borders);
8438 * Gets the width of the padding(s) for the specified side(s)
8439 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8440 * passing lr would get the padding (l)eft + the padding (r)ight.
8441 * @return {Number} The padding of the sides passed added together
8443 getPadding : function(side){
8444 return this.addStyles(side, El.paddings);
8448 * Set positioning with an object returned by getPositioning().
8449 * @param {Object} posCfg
8450 * @return {Roo.Element} this
8452 setPositioning : function(pc){
8453 this.applyStyles(pc);
8454 if(pc.right == "auto"){
8455 this.dom.style.right = "";
8457 if(pc.bottom == "auto"){
8458 this.dom.style.bottom = "";
8464 fixDisplay : function(){
8465 if(this.getStyle("display") == "none"){
8466 this.setStyle("visibility", "hidden");
8467 this.setStyle("display", this.originalDisplay); // first try reverting to default
8468 if(this.getStyle("display") == "none"){ // if that fails, default to block
8469 this.setStyle("display", "block");
8475 * Quick set left and top adding default units
8476 * @param {String} left The left CSS property value
8477 * @param {String} top The top CSS property value
8478 * @return {Roo.Element} this
8480 setLeftTop : function(left, top){
8481 this.dom.style.left = this.addUnits(left);
8482 this.dom.style.top = this.addUnits(top);
8487 * Move this element relative to its current position.
8488 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8489 * @param {Number} distance How far to move the element in pixels
8490 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8491 * @return {Roo.Element} this
8493 move : function(direction, distance, animate){
8494 var xy = this.getXY();
8495 direction = direction.toLowerCase();
8499 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8503 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8508 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8513 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8520 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8521 * @return {Roo.Element} this
8524 if(!this.isClipped){
8525 this.isClipped = true;
8526 this.originalClip = {
8527 "o": this.getStyle("overflow"),
8528 "x": this.getStyle("overflow-x"),
8529 "y": this.getStyle("overflow-y")
8531 this.setStyle("overflow", "hidden");
8532 this.setStyle("overflow-x", "hidden");
8533 this.setStyle("overflow-y", "hidden");
8539 * Return clipping (overflow) to original clipping before clip() was called
8540 * @return {Roo.Element} this
8542 unclip : function(){
8544 this.isClipped = false;
8545 var o = this.originalClip;
8546 if(o.o){this.setStyle("overflow", o.o);}
8547 if(o.x){this.setStyle("overflow-x", o.x);}
8548 if(o.y){this.setStyle("overflow-y", o.y);}
8555 * Gets the x,y coordinates specified by the anchor position on the element.
8556 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8557 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8558 * {width: (target width), height: (target height)} (defaults to the element's current size)
8559 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8560 * @return {Array} [x, y] An array containing the element's x and y coordinates
8562 getAnchorXY : function(anchor, local, s){
8563 //Passing a different size is useful for pre-calculating anchors,
8564 //especially for anchored animations that change the el size.
8566 var w, h, vp = false;
8569 if(d == document.body || d == document){
8571 w = D.getViewWidth(); h = D.getViewHeight();
8573 w = this.getWidth(); h = this.getHeight();
8576 w = s.width; h = s.height;
8578 var x = 0, y = 0, r = Math.round;
8579 switch((anchor || "tl").toLowerCase()){
8621 var sc = this.getScroll();
8622 return [x + sc.left, y + sc.top];
8624 //Add the element's offset xy
8625 var o = this.getXY();
8626 return [x+o[0], y+o[1]];
8630 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8631 * supported position values.
8632 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8633 * @param {String} position The position to align to.
8634 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8635 * @return {Array} [x, y]
8637 getAlignToXY : function(el, p, o)
8642 throw "Element.alignTo with an element that doesn't exist";
8644 var c = false; //constrain to viewport
8645 var p1 = "", p2 = "";
8652 }else if(p.indexOf("-") == -1){
8655 p = p.toLowerCase();
8656 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8658 throw "Element.alignTo with an invalid alignment " + p;
8660 p1 = m[1]; p2 = m[2]; c = !!m[3];
8662 //Subtract the aligned el's internal xy from the target's offset xy
8663 //plus custom offset to get the aligned el's new offset xy
8664 var a1 = this.getAnchorXY(p1, true);
8665 var a2 = el.getAnchorXY(p2, false);
8666 var x = a2[0] - a1[0] + o[0];
8667 var y = a2[1] - a1[1] + o[1];
8669 //constrain the aligned el to viewport if necessary
8670 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8671 // 5px of margin for ie
8672 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8674 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8675 //perpendicular to the vp border, allow the aligned el to slide on that border,
8676 //otherwise swap the aligned el to the opposite border of the target.
8677 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8678 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8679 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8680 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8683 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8684 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8686 if((x+w) > dw + scrollX){
8687 x = swapX ? r.left-w : dw+scrollX-w;
8690 x = swapX ? r.right : scrollX;
8692 if((y+h) > dh + scrollY){
8693 y = swapY ? r.top-h : dh+scrollY-h;
8696 y = swapY ? r.bottom : scrollY;
8703 getConstrainToXY : function(){
8704 var os = {top:0, left:0, bottom:0, right: 0};
8706 return function(el, local, offsets, proposedXY){
8708 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8710 var vw, vh, vx = 0, vy = 0;
8711 if(el.dom == document.body || el.dom == document){
8712 vw = Roo.lib.Dom.getViewWidth();
8713 vh = Roo.lib.Dom.getViewHeight();
8715 vw = el.dom.clientWidth;
8716 vh = el.dom.clientHeight;
8718 var vxy = el.getXY();
8724 var s = el.getScroll();
8726 vx += offsets.left + s.left;
8727 vy += offsets.top + s.top;
8729 vw -= offsets.right;
8730 vh -= offsets.bottom;
8735 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8736 var x = xy[0], y = xy[1];
8737 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8739 // only move it if it needs it
8742 // first validate right/bottom
8751 // then make sure top/left isn't negative
8760 return moved ? [x, y] : false;
8765 adjustForConstraints : function(xy, parent, offsets){
8766 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8770 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8771 * document it aligns it to the viewport.
8772 * The position parameter is optional, and can be specified in any one of the following formats:
8774 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8775 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8776 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8777 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8778 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8779 * element's anchor point, and the second value is used as the target's anchor point.</li>
8781 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8782 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8783 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8784 * that specified in order to enforce the viewport constraints.
8785 * Following are all of the supported anchor positions:
8788 ----- -----------------------------
8789 tl The top left corner (default)
8790 t The center of the top edge
8791 tr The top right corner
8792 l The center of the left edge
8793 c In the center of the element
8794 r The center of the right edge
8795 bl The bottom left corner
8796 b The center of the bottom edge
8797 br The bottom right corner
8801 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8802 el.alignTo("other-el");
8804 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8805 el.alignTo("other-el", "tr?");
8807 // align the bottom right corner of el with the center left edge of other-el
8808 el.alignTo("other-el", "br-l?");
8810 // align the center of el with the bottom left corner of other-el and
8811 // adjust the x position by -6 pixels (and the y position by 0)
8812 el.alignTo("other-el", "c-bl", [-6, 0]);
8814 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8815 * @param {String} position The position to align to.
8816 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8817 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8818 * @return {Roo.Element} this
8820 alignTo : function(element, position, offsets, animate){
8821 var xy = this.getAlignToXY(element, position, offsets);
8822 this.setXY(xy, this.preanim(arguments, 3));
8827 * Anchors an element to another element and realigns it when the window is resized.
8828 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8829 * @param {String} position The position to align to.
8830 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8831 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8832 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8833 * is a number, it is used as the buffer delay (defaults to 50ms).
8834 * @param {Function} callback The function to call after the animation finishes
8835 * @return {Roo.Element} this
8837 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8838 var action = function(){
8839 this.alignTo(el, alignment, offsets, animate);
8840 Roo.callback(callback, this);
8842 Roo.EventManager.onWindowResize(action, this);
8843 var tm = typeof monitorScroll;
8844 if(tm != 'undefined'){
8845 Roo.EventManager.on(window, 'scroll', action, this,
8846 {buffer: tm == 'number' ? monitorScroll : 50});
8848 action.call(this); // align immediately
8852 * Clears any opacity settings from this element. Required in some cases for IE.
8853 * @return {Roo.Element} this
8855 clearOpacity : function(){
8856 if (window.ActiveXObject) {
8857 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8858 this.dom.style.filter = "";
8861 this.dom.style.opacity = "";
8862 this.dom.style["-moz-opacity"] = "";
8863 this.dom.style["-khtml-opacity"] = "";
8869 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8870 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8871 * @return {Roo.Element} this
8873 hide : function(animate){
8874 this.setVisible(false, this.preanim(arguments, 0));
8879 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8880 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8881 * @return {Roo.Element} this
8883 show : function(animate){
8884 this.setVisible(true, this.preanim(arguments, 0));
8889 * @private Test if size has a unit, otherwise appends the default
8891 addUnits : function(size){
8892 return Roo.Element.addUnits(size, this.defaultUnit);
8896 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8897 * @return {Roo.Element} this
8899 beginMeasure : function(){
8901 if(el.offsetWidth || el.offsetHeight){
8902 return this; // offsets work already
8905 var p = this.dom, b = document.body; // start with this element
8906 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8907 var pe = Roo.get(p);
8908 if(pe.getStyle('display') == 'none'){
8909 changed.push({el: p, visibility: pe.getStyle("visibility")});
8910 p.style.visibility = "hidden";
8911 p.style.display = "block";
8915 this._measureChanged = changed;
8921 * Restores displays to before beginMeasure was called
8922 * @return {Roo.Element} this
8924 endMeasure : function(){
8925 var changed = this._measureChanged;
8927 for(var i = 0, len = changed.length; i < len; i++) {
8929 r.el.style.visibility = r.visibility;
8930 r.el.style.display = "none";
8932 this._measureChanged = null;
8938 * Update the innerHTML of this element, optionally searching for and processing scripts
8939 * @param {String} html The new HTML
8940 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8941 * @param {Function} callback For async script loading you can be noticed when the update completes
8942 * @return {Roo.Element} this
8944 update : function(html, loadScripts, callback){
8945 if(typeof html == "undefined"){
8948 if(loadScripts !== true){
8949 this.dom.innerHTML = html;
8950 if(typeof callback == "function"){
8958 html += '<span id="' + id + '"></span>';
8960 E.onAvailable(id, function(){
8961 var hd = document.getElementsByTagName("head")[0];
8962 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8963 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8964 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8967 while(match = re.exec(html)){
8968 var attrs = match[1];
8969 var srcMatch = attrs ? attrs.match(srcRe) : false;
8970 if(srcMatch && srcMatch[2]){
8971 var s = document.createElement("script");
8972 s.src = srcMatch[2];
8973 var typeMatch = attrs.match(typeRe);
8974 if(typeMatch && typeMatch[2]){
8975 s.type = typeMatch[2];
8978 }else if(match[2] && match[2].length > 0){
8979 if(window.execScript) {
8980 window.execScript(match[2]);
8988 window.eval(match[2]);
8992 var el = document.getElementById(id);
8993 if(el){el.parentNode.removeChild(el);}
8994 if(typeof callback == "function"){
8998 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9003 * Direct access to the UpdateManager update() method (takes the same parameters).
9004 * @param {String/Function} url The url for this request or a function to call to get the url
9005 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
9006 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9007 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
9008 * @return {Roo.Element} this
9011 var um = this.getUpdateManager();
9012 um.update.apply(um, arguments);
9017 * Gets this element's UpdateManager
9018 * @return {Roo.UpdateManager} The UpdateManager
9020 getUpdateManager : function(){
9021 if(!this.updateManager){
9022 this.updateManager = new Roo.UpdateManager(this);
9024 return this.updateManager;
9028 * Disables text selection for this element (normalized across browsers)
9029 * @return {Roo.Element} this
9031 unselectable : function(){
9032 this.dom.unselectable = "on";
9033 this.swallowEvent("selectstart", true);
9034 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9035 this.addClass("x-unselectable");
9040 * Calculates the x, y to center this element on the screen
9041 * @return {Array} The x, y values [x, y]
9043 getCenterXY : function(){
9044 return this.getAlignToXY(document, 'c-c');
9048 * Centers the Element in either the viewport, or another Element.
9049 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9051 center : function(centerIn){
9052 this.alignTo(centerIn || document, 'c-c');
9057 * Tests various css rules/browsers to determine if this element uses a border box
9060 isBorderBox : function(){
9061 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9065 * Return a box {x, y, width, height} that can be used to set another elements
9066 * size/location to match this element.
9067 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9068 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9069 * @return {Object} box An object in the format {x, y, width, height}
9071 getBox : function(contentBox, local){
9076 var left = parseInt(this.getStyle("left"), 10) || 0;
9077 var top = parseInt(this.getStyle("top"), 10) || 0;
9080 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9082 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9084 var l = this.getBorderWidth("l")+this.getPadding("l");
9085 var r = this.getBorderWidth("r")+this.getPadding("r");
9086 var t = this.getBorderWidth("t")+this.getPadding("t");
9087 var b = this.getBorderWidth("b")+this.getPadding("b");
9088 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
9090 bx.right = bx.x + bx.width;
9091 bx.bottom = bx.y + bx.height;
9096 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9097 for more information about the sides.
9098 * @param {String} sides
9101 getFrameWidth : function(sides, onlyContentBox){
9102 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9106 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
9107 * @param {Object} box The box to fill {x, y, width, height}
9108 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9109 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9110 * @return {Roo.Element} this
9112 setBox : function(box, adjust, animate){
9113 var w = box.width, h = box.height;
9114 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9115 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9116 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9118 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9123 * Forces the browser to repaint this element
9124 * @return {Roo.Element} this
9126 repaint : function(){
9128 this.addClass("x-repaint");
9129 setTimeout(function(){
9130 Roo.get(dom).removeClass("x-repaint");
9136 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9137 * then it returns the calculated width of the sides (see getPadding)
9138 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9139 * @return {Object/Number}
9141 getMargins : function(side){
9144 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9145 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9146 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9147 right: parseInt(this.getStyle("margin-right"), 10) || 0
9150 return this.addStyles(side, El.margins);
9155 addStyles : function(sides, styles){
9157 for(var i = 0, len = sides.length; i < len; i++){
9158 v = this.getStyle(styles[sides.charAt(i)]);
9160 w = parseInt(v, 10);
9168 * Creates a proxy element of this element
9169 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9170 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9171 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9172 * @return {Roo.Element} The new proxy element
9174 createProxy : function(config, renderTo, matchBox){
9176 renderTo = Roo.getDom(renderTo);
9178 renderTo = document.body;
9180 config = typeof config == "object" ?
9181 config : {tag : "div", cls: config};
9182 var proxy = Roo.DomHelper.append(renderTo, config, true);
9184 proxy.setBox(this.getBox());
9190 * Puts a mask over this element to disable user interaction. Requires core.css.
9191 * This method can only be applied to elements which accept child nodes.
9192 * @param {String} msg (optional) A message to display in the mask
9193 * @param {String} msgCls (optional) A css class to apply to the msg element
9194 * @return {Element} The mask element
9196 mask : function(msg, msgCls)
9198 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9199 this.setStyle("position", "relative");
9202 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9205 this.addClass("x-masked");
9206 this._mask.setDisplayed(true);
9211 while (dom && dom.style) {
9212 if (!isNaN(parseInt(dom.style.zIndex))) {
9213 z = Math.max(z, parseInt(dom.style.zIndex));
9215 dom = dom.parentNode;
9217 // if we are masking the body - then it hides everything..
9218 if (this.dom == document.body) {
9220 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9221 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9224 if(typeof msg == 'string'){
9226 this._maskMsg = Roo.DomHelper.append(this.dom, {
9227 cls: "roo-el-mask-msg",
9231 cls: 'fa fa-spinner fa-spin'
9239 var mm = this._maskMsg;
9240 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9241 if (mm.dom.lastChild) { // weird IE issue?
9242 mm.dom.lastChild.innerHTML = msg;
9244 mm.setDisplayed(true);
9246 mm.setStyle('z-index', z + 102);
9248 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9249 this._mask.setHeight(this.getHeight());
9251 this._mask.setStyle('z-index', z + 100);
9257 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9258 * it is cached for reuse.
9260 unmask : function(removeEl){
9262 if(removeEl === true){
9263 this._mask.remove();
9266 this._maskMsg.remove();
9267 delete this._maskMsg;
9270 this._mask.setDisplayed(false);
9272 this._maskMsg.setDisplayed(false);
9276 this.removeClass("x-masked");
9280 * Returns true if this element is masked
9283 isMasked : function(){
9284 return this._mask && this._mask.isVisible();
9288 * Creates an iframe shim for this element to keep selects and other windowed objects from
9290 * @return {Roo.Element} The new shim element
9292 createShim : function(){
9293 var el = document.createElement('iframe');
9294 el.frameBorder = 'no';
9295 el.className = 'roo-shim';
9296 if(Roo.isIE && Roo.isSecure){
9297 el.src = Roo.SSL_SECURE_URL;
9299 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9300 shim.autoBoxAdjust = false;
9305 * Removes this element from the DOM and deletes it from the cache
9307 remove : function(){
9308 if(this.dom.parentNode){
9309 this.dom.parentNode.removeChild(this.dom);
9311 delete El.cache[this.dom.id];
9315 * Sets up event handlers to add and remove a css class when the mouse is over this element
9316 * @param {String} className
9317 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9318 * mouseout events for children elements
9319 * @return {Roo.Element} this
9321 addClassOnOver : function(className, preventFlicker){
9322 this.on("mouseover", function(){
9323 Roo.fly(this, '_internal').addClass(className);
9325 var removeFn = function(e){
9326 if(preventFlicker !== true || !e.within(this, true)){
9327 Roo.fly(this, '_internal').removeClass(className);
9330 this.on("mouseout", removeFn, this.dom);
9335 * Sets up event handlers to add and remove a css class when this element has the focus
9336 * @param {String} className
9337 * @return {Roo.Element} this
9339 addClassOnFocus : function(className){
9340 this.on("focus", function(){
9341 Roo.fly(this, '_internal').addClass(className);
9343 this.on("blur", function(){
9344 Roo.fly(this, '_internal').removeClass(className);
9349 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9350 * @param {String} className
9351 * @return {Roo.Element} this
9353 addClassOnClick : function(className){
9355 this.on("mousedown", function(){
9356 Roo.fly(dom, '_internal').addClass(className);
9357 var d = Roo.get(document);
9358 var fn = function(){
9359 Roo.fly(dom, '_internal').removeClass(className);
9360 d.removeListener("mouseup", fn);
9362 d.on("mouseup", fn);
9368 * Stops the specified event from bubbling and optionally prevents the default action
9369 * @param {String} eventName
9370 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9371 * @return {Roo.Element} this
9373 swallowEvent : function(eventName, preventDefault){
9374 var fn = function(e){
9375 e.stopPropagation();
9380 if(eventName instanceof Array){
9381 for(var i = 0, len = eventName.length; i < len; i++){
9382 this.on(eventName[i], fn);
9386 this.on(eventName, fn);
9393 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9396 * Sizes this element to its parent element's dimensions performing
9397 * neccessary box adjustments.
9398 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9399 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9400 * @return {Roo.Element} this
9402 fitToParent : function(monitorResize, targetParent) {
9403 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9404 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9405 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9408 var p = Roo.get(targetParent || this.dom.parentNode);
9409 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9410 if (monitorResize === true) {
9411 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9412 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9418 * Gets the next sibling, skipping text nodes
9419 * @return {HTMLElement} The next sibling or null
9421 getNextSibling : function(){
9422 var n = this.dom.nextSibling;
9423 while(n && n.nodeType != 1){
9430 * Gets the previous sibling, skipping text nodes
9431 * @return {HTMLElement} The previous sibling or null
9433 getPrevSibling : function(){
9434 var n = this.dom.previousSibling;
9435 while(n && n.nodeType != 1){
9436 n = n.previousSibling;
9443 * Appends the passed element(s) to this element
9444 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9445 * @return {Roo.Element} this
9447 appendChild: function(el){
9454 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9455 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9456 * automatically generated with the specified attributes.
9457 * @param {HTMLElement} insertBefore (optional) a child element of this element
9458 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9459 * @return {Roo.Element} The new child element
9461 createChild: function(config, insertBefore, returnDom){
9462 config = config || {tag:'div'};
9464 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9466 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9470 * Appends this element to the passed element
9471 * @param {String/HTMLElement/Element} el The new parent element
9472 * @return {Roo.Element} this
9474 appendTo: function(el){
9475 el = Roo.getDom(el);
9476 el.appendChild(this.dom);
9481 * Inserts this element before the passed element in the DOM
9482 * @param {String/HTMLElement/Element} el The element to insert before
9483 * @return {Roo.Element} this
9485 insertBefore: function(el){
9486 el = Roo.getDom(el);
9487 el.parentNode.insertBefore(this.dom, el);
9492 * Inserts this element after the passed element in the DOM
9493 * @param {String/HTMLElement/Element} el The element to insert after
9494 * @return {Roo.Element} this
9496 insertAfter: function(el){
9497 el = Roo.getDom(el);
9498 el.parentNode.insertBefore(this.dom, el.nextSibling);
9503 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9504 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9505 * @return {Roo.Element} The new child
9507 insertFirst: function(el, returnDom){
9509 if(typeof el == 'object' && !el.nodeType){ // dh config
9510 return this.createChild(el, this.dom.firstChild, returnDom);
9512 el = Roo.getDom(el);
9513 this.dom.insertBefore(el, this.dom.firstChild);
9514 return !returnDom ? Roo.get(el) : el;
9519 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9520 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9521 * @param {String} where (optional) 'before' or 'after' defaults to before
9522 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9523 * @return {Roo.Element} the inserted Element
9525 insertSibling: function(el, where, returnDom){
9526 where = where ? where.toLowerCase() : 'before';
9528 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9530 if(typeof el == 'object' && !el.nodeType){ // dh config
9531 if(where == 'after' && !this.dom.nextSibling){
9532 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9534 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9538 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9539 where == 'before' ? this.dom : this.dom.nextSibling);
9548 * Creates and wraps this element with another element
9549 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9550 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9551 * @return {HTMLElement/Element} The newly created wrapper element
9553 wrap: function(config, returnDom){
9555 config = {tag: "div"};
9557 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9558 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9563 * Replaces the passed element with this element
9564 * @param {String/HTMLElement/Element} el The element to replace
9565 * @return {Roo.Element} this
9567 replace: function(el){
9569 this.insertBefore(el);
9575 * Inserts an html fragment into this element
9576 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9577 * @param {String} html The HTML fragment
9578 * @param {Boolean} returnEl True to return an Roo.Element
9579 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9581 insertHtml : function(where, html, returnEl){
9582 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9583 return returnEl ? Roo.get(el) : el;
9587 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9588 * @param {Object} o The object with the attributes
9589 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9590 * @return {Roo.Element} this
9592 set : function(o, useSet){
9594 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9596 if(attr == "style" || typeof o[attr] == "function") { continue; }
9598 el.className = o["cls"];
9601 el.setAttribute(attr, o[attr]);
9608 Roo.DomHelper.applyStyles(el, o.style);
9614 * Convenience method for constructing a KeyMap
9615 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9616 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9617 * @param {Function} fn The function to call
9618 * @param {Object} scope (optional) The scope of the function
9619 * @return {Roo.KeyMap} The KeyMap created
9621 addKeyListener : function(key, fn, scope){
9623 if(typeof key != "object" || key instanceof Array){
9639 return new Roo.KeyMap(this, config);
9643 * Creates a KeyMap for this element
9644 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9645 * @return {Roo.KeyMap} The KeyMap created
9647 addKeyMap : function(config){
9648 return new Roo.KeyMap(this, config);
9652 * Returns true if this element is scrollable.
9655 isScrollable : function(){
9657 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9661 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9662 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9663 * @param {Number} value The new scroll value
9664 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9665 * @return {Element} this
9668 scrollTo : function(side, value, animate){
9669 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9671 this.dom[prop] = value;
9673 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9674 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9680 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9681 * within this element's scrollable range.
9682 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9683 * @param {Number} distance How far to scroll the element in pixels
9684 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9685 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9686 * was scrolled as far as it could go.
9688 scroll : function(direction, distance, animate){
9689 if(!this.isScrollable()){
9693 var l = el.scrollLeft, t = el.scrollTop;
9694 var w = el.scrollWidth, h = el.scrollHeight;
9695 var cw = el.clientWidth, ch = el.clientHeight;
9696 direction = direction.toLowerCase();
9697 var scrolled = false;
9698 var a = this.preanim(arguments, 2);
9703 var v = Math.min(l + distance, w-cw);
9704 this.scrollTo("left", v, a);
9711 var v = Math.max(l - distance, 0);
9712 this.scrollTo("left", v, a);
9720 var v = Math.max(t - distance, 0);
9721 this.scrollTo("top", v, a);
9729 var v = Math.min(t + distance, h-ch);
9730 this.scrollTo("top", v, a);
9739 * Translates the passed page coordinates into left/top css values for this element
9740 * @param {Number/Array} x The page x or an array containing [x, y]
9741 * @param {Number} y The page y
9742 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9744 translatePoints : function(x, y){
9745 if(typeof x == 'object' || x instanceof Array){
9748 var p = this.getStyle('position');
9749 var o = this.getXY();
9751 var l = parseInt(this.getStyle('left'), 10);
9752 var t = parseInt(this.getStyle('top'), 10);
9755 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9758 t = (p == "relative") ? 0 : this.dom.offsetTop;
9761 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9765 * Returns the current scroll position of the element.
9766 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9768 getScroll : function(){
9769 var d = this.dom, doc = document;
9770 if(d == doc || d == doc.body){
9771 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9772 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9773 return {left: l, top: t};
9775 return {left: d.scrollLeft, top: d.scrollTop};
9780 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9781 * are convert to standard 6 digit hex color.
9782 * @param {String} attr The css attribute
9783 * @param {String} defaultValue The default value to use when a valid color isn't found
9784 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9787 getColor : function(attr, defaultValue, prefix){
9788 var v = this.getStyle(attr);
9789 if(!v || v == "transparent" || v == "inherit") {
9790 return defaultValue;
9792 var color = typeof prefix == "undefined" ? "#" : prefix;
9793 if(v.substr(0, 4) == "rgb("){
9794 var rvs = v.slice(4, v.length -1).split(",");
9795 for(var i = 0; i < 3; i++){
9796 var h = parseInt(rvs[i]).toString(16);
9803 if(v.substr(0, 1) == "#"){
9805 for(var i = 1; i < 4; i++){
9806 var c = v.charAt(i);
9809 }else if(v.length == 7){
9810 color += v.substr(1);
9814 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9818 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9819 * gradient background, rounded corners and a 4-way shadow.
9820 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9821 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9822 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9823 * @return {Roo.Element} this
9825 boxWrap : function(cls){
9826 cls = cls || 'x-box';
9827 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9828 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9833 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9834 * @param {String} namespace The namespace in which to look for the attribute
9835 * @param {String} name The attribute name
9836 * @return {String} The attribute value
9838 getAttributeNS : Roo.isIE ? function(ns, name){
9840 var type = typeof d[ns+":"+name];
9841 if(type != 'undefined' && type != 'unknown'){
9842 return d[ns+":"+name];
9845 } : function(ns, name){
9847 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9852 * Sets or Returns the value the dom attribute value
9853 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9854 * @param {String} value (optional) The value to set the attribute to
9855 * @return {String} The attribute value
9857 attr : function(name){
9858 if (arguments.length > 1) {
9859 this.dom.setAttribute(name, arguments[1]);
9860 return arguments[1];
9862 if (typeof(name) == 'object') {
9863 for(var i in name) {
9864 this.attr(i, name[i]);
9870 if (!this.dom.hasAttribute(name)) {
9873 return this.dom.getAttribute(name);
9880 var ep = El.prototype;
9883 * Appends an event handler (Shorthand for addListener)
9884 * @param {String} eventName The type of event to append
9885 * @param {Function} fn The method the event invokes
9886 * @param {Object} scope (optional) The scope (this object) of the fn
9887 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9890 ep.on = ep.addListener;
9892 ep.mon = ep.addListener;
9895 * Removes an event handler from this element (shorthand for removeListener)
9896 * @param {String} eventName the type of event to remove
9897 * @param {Function} fn the method the event invokes
9898 * @return {Roo.Element} this
9901 ep.un = ep.removeListener;
9904 * true to automatically adjust width and height settings for box-model issues (default to true)
9906 ep.autoBoxAdjust = true;
9909 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9912 El.addUnits = function(v, defaultUnit){
9913 if(v === "" || v == "auto"){
9916 if(v === undefined){
9919 if(typeof v == "number" || !El.unitPattern.test(v)){
9920 return v + (defaultUnit || 'px');
9925 // special markup used throughout Roo when box wrapping elements
9926 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9928 * Visibility mode constant - Use visibility to hide element
9934 * Visibility mode constant - Use display to hide element
9940 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9941 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9942 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9954 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9955 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9956 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9957 * @return {Element} The Element object
9960 El.get = function(el){
9962 if(!el){ return null; }
9963 if(typeof el == "string"){ // element id
9964 if(!(elm = document.getElementById(el))){
9967 if(ex = El.cache[el]){
9970 ex = El.cache[el] = new El(elm);
9973 }else if(el.tagName){ // dom element
9977 if(ex = El.cache[id]){
9980 ex = El.cache[id] = new El(el);
9983 }else if(el instanceof El){
9985 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9986 // catch case where it hasn't been appended
9987 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9990 }else if(el.isComposite){
9992 }else if(el instanceof Array){
9993 return El.select(el);
9994 }else if(el == document){
9995 // create a bogus element object representing the document object
9997 var f = function(){};
9998 f.prototype = El.prototype;
10000 docEl.dom = document;
10008 El.uncache = function(el){
10009 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10011 delete El.cache[a[i].id || a[i]];
10017 // Garbage collection - uncache elements/purge listeners on orphaned elements
10018 // so we don't hold a reference and cause the browser to retain them
10019 El.garbageCollect = function(){
10020 if(!Roo.enableGarbageCollector){
10021 clearInterval(El.collectorThread);
10024 for(var eid in El.cache){
10025 var el = El.cache[eid], d = el.dom;
10026 // -------------------------------------------------------
10027 // Determining what is garbage:
10028 // -------------------------------------------------------
10030 // dom node is null, definitely garbage
10031 // -------------------------------------------------------
10033 // no parentNode == direct orphan, definitely garbage
10034 // -------------------------------------------------------
10035 // !d.offsetParent && !document.getElementById(eid)
10036 // display none elements have no offsetParent so we will
10037 // also try to look it up by it's id. However, check
10038 // offsetParent first so we don't do unneeded lookups.
10039 // This enables collection of elements that are not orphans
10040 // directly, but somewhere up the line they have an orphan
10042 // -------------------------------------------------------
10043 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10044 delete El.cache[eid];
10045 if(d && Roo.enableListenerCollection){
10051 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10055 El.Flyweight = function(dom){
10058 El.Flyweight.prototype = El.prototype;
10060 El._flyweights = {};
10062 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10063 * the dom node can be overwritten by other code.
10064 * @param {String/HTMLElement} el The dom node or id
10065 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10066 * prevent conflicts (e.g. internally Roo uses "_internal")
10068 * @return {Element} The shared Element object
10070 El.fly = function(el, named){
10071 named = named || '_global';
10072 el = Roo.getDom(el);
10076 if(!El._flyweights[named]){
10077 El._flyweights[named] = new El.Flyweight();
10079 El._flyweights[named].dom = el;
10080 return El._flyweights[named];
10084 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10085 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10086 * Shorthand of {@link Roo.Element#get}
10087 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10088 * @return {Element} The Element object
10094 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10095 * the dom node can be overwritten by other code.
10096 * Shorthand of {@link Roo.Element#fly}
10097 * @param {String/HTMLElement} el The dom node or id
10098 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10099 * prevent conflicts (e.g. internally Roo uses "_internal")
10101 * @return {Element} The shared Element object
10107 // speedy lookup for elements never to box adjust
10108 var noBoxAdjust = Roo.isStrict ? {
10111 input:1, select:1, textarea:1
10113 if(Roo.isIE || Roo.isGecko){
10114 noBoxAdjust['button'] = 1;
10118 Roo.EventManager.on(window, 'unload', function(){
10120 delete El._flyweights;
10128 Roo.Element.selectorFunction = Roo.DomQuery.select;
10131 Roo.Element.select = function(selector, unique, root){
10133 if(typeof selector == "string"){
10134 els = Roo.Element.selectorFunction(selector, root);
10135 }else if(selector.length !== undefined){
10138 throw "Invalid selector";
10140 if(unique === true){
10141 return new Roo.CompositeElement(els);
10143 return new Roo.CompositeElementLite(els);
10147 * Selects elements based on the passed CSS selector to enable working on them as 1.
10148 * @param {String/Array} selector The CSS selector or an array of elements
10149 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10150 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10151 * @return {CompositeElementLite/CompositeElement}
10155 Roo.select = Roo.Element.select;
10172 * Ext JS Library 1.1.1
10173 * Copyright(c) 2006-2007, Ext JS, LLC.
10175 * Originally Released Under LGPL - original licence link has changed is not relivant.
10178 * <script type="text/javascript">
10183 //Notifies Element that fx methods are available
10184 Roo.enableFx = true;
10188 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10189 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10190 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10191 * Element effects to work.</p><br/>
10193 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10194 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10195 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10196 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10197 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10198 * expected results and should be done with care.</p><br/>
10200 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10201 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10204 ----- -----------------------------
10205 tl The top left corner
10206 t The center of the top edge
10207 tr The top right corner
10208 l The center of the left edge
10209 r The center of the right edge
10210 bl The bottom left corner
10211 b The center of the bottom edge
10212 br The bottom right corner
10214 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10215 * below are common options that can be passed to any Fx method.</b>
10216 * @cfg {Function} callback A function called when the effect is finished
10217 * @cfg {Object} scope The scope of the effect function
10218 * @cfg {String} easing A valid Easing value for the effect
10219 * @cfg {String} afterCls A css class to apply after the effect
10220 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10221 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10222 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10223 * effects that end with the element being visually hidden, ignored otherwise)
10224 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10225 * a function which returns such a specification that will be applied to the Element after the effect finishes
10226 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10227 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
10228 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10232 * Slides the element into view. An anchor point can be optionally passed to set the point of
10233 * origin for the slide effect. This function automatically handles wrapping the element with
10234 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10237 // default: slide the element in from the top
10240 // custom: slide the element in from the right with a 2-second duration
10241 el.slideIn('r', { duration: 2 });
10243 // common config options shown with default values
10249 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10250 * @param {Object} options (optional) Object literal with any of the Fx config options
10251 * @return {Roo.Element} The Element
10253 slideIn : function(anchor, o){
10254 var el = this.getFxEl();
10257 el.queueFx(o, function(){
10259 anchor = anchor || "t";
10261 // fix display to visibility
10264 // restore values after effect
10265 var r = this.getFxRestore();
10266 var b = this.getBox();
10267 // fixed size for slide
10271 var wrap = this.fxWrap(r.pos, o, "hidden");
10273 var st = this.dom.style;
10274 st.visibility = "visible";
10275 st.position = "absolute";
10277 // clear out temp styles after slide and unwrap
10278 var after = function(){
10279 el.fxUnwrap(wrap, r.pos, o);
10280 st.width = r.width;
10281 st.height = r.height;
10284 // time to calc the positions
10285 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10287 switch(anchor.toLowerCase()){
10289 wrap.setSize(b.width, 0);
10290 st.left = st.bottom = "0";
10294 wrap.setSize(0, b.height);
10295 st.right = st.top = "0";
10299 wrap.setSize(0, b.height);
10300 wrap.setX(b.right);
10301 st.left = st.top = "0";
10302 a = {width: bw, points: pt};
10305 wrap.setSize(b.width, 0);
10306 wrap.setY(b.bottom);
10307 st.left = st.top = "0";
10308 a = {height: bh, points: pt};
10311 wrap.setSize(0, 0);
10312 st.right = st.bottom = "0";
10313 a = {width: bw, height: bh};
10316 wrap.setSize(0, 0);
10317 wrap.setY(b.y+b.height);
10318 st.right = st.top = "0";
10319 a = {width: bw, height: bh, points: pt};
10322 wrap.setSize(0, 0);
10323 wrap.setXY([b.right, b.bottom]);
10324 st.left = st.top = "0";
10325 a = {width: bw, height: bh, points: pt};
10328 wrap.setSize(0, 0);
10329 wrap.setX(b.x+b.width);
10330 st.left = st.bottom = "0";
10331 a = {width: bw, height: bh, points: pt};
10334 this.dom.style.visibility = "visible";
10337 arguments.callee.anim = wrap.fxanim(a,
10347 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10348 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10349 * 'hidden') but block elements will still take up space in the document. The element must be removed
10350 * from the DOM using the 'remove' config option if desired. This function automatically handles
10351 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10354 // default: slide the element out to the top
10357 // custom: slide the element out to the right with a 2-second duration
10358 el.slideOut('r', { duration: 2 });
10360 // common config options shown with default values
10368 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10369 * @param {Object} options (optional) Object literal with any of the Fx config options
10370 * @return {Roo.Element} The Element
10372 slideOut : function(anchor, o){
10373 var el = this.getFxEl();
10376 el.queueFx(o, function(){
10378 anchor = anchor || "t";
10380 // restore values after effect
10381 var r = this.getFxRestore();
10383 var b = this.getBox();
10384 // fixed size for slide
10388 var wrap = this.fxWrap(r.pos, o, "visible");
10390 var st = this.dom.style;
10391 st.visibility = "visible";
10392 st.position = "absolute";
10396 var after = function(){
10398 el.setDisplayed(false);
10403 el.fxUnwrap(wrap, r.pos, o);
10405 st.width = r.width;
10406 st.height = r.height;
10411 var a, zero = {to: 0};
10412 switch(anchor.toLowerCase()){
10414 st.left = st.bottom = "0";
10415 a = {height: zero};
10418 st.right = st.top = "0";
10422 st.left = st.top = "0";
10423 a = {width: zero, points: {to:[b.right, b.y]}};
10426 st.left = st.top = "0";
10427 a = {height: zero, points: {to:[b.x, b.bottom]}};
10430 st.right = st.bottom = "0";
10431 a = {width: zero, height: zero};
10434 st.right = st.top = "0";
10435 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10438 st.left = st.top = "0";
10439 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10442 st.left = st.bottom = "0";
10443 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10447 arguments.callee.anim = wrap.fxanim(a,
10457 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10458 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10459 * The element must be removed from the DOM using the 'remove' config option if desired.
10465 // common config options shown with default values
10473 * @param {Object} options (optional) Object literal with any of the Fx config options
10474 * @return {Roo.Element} The Element
10476 puff : function(o){
10477 var el = this.getFxEl();
10480 el.queueFx(o, function(){
10481 this.clearOpacity();
10484 // restore values after effect
10485 var r = this.getFxRestore();
10486 var st = this.dom.style;
10488 var after = function(){
10490 el.setDisplayed(false);
10497 el.setPositioning(r.pos);
10498 st.width = r.width;
10499 st.height = r.height;
10504 var width = this.getWidth();
10505 var height = this.getHeight();
10507 arguments.callee.anim = this.fxanim({
10508 width : {to: this.adjustWidth(width * 2)},
10509 height : {to: this.adjustHeight(height * 2)},
10510 points : {by: [-(width * .5), -(height * .5)]},
10512 fontSize: {to:200, unit: "%"}
10523 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10524 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10525 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10531 // all config options shown with default values
10539 * @param {Object} options (optional) Object literal with any of the Fx config options
10540 * @return {Roo.Element} The Element
10542 switchOff : function(o){
10543 var el = this.getFxEl();
10546 el.queueFx(o, function(){
10547 this.clearOpacity();
10550 // restore values after effect
10551 var r = this.getFxRestore();
10552 var st = this.dom.style;
10554 var after = function(){
10556 el.setDisplayed(false);
10562 el.setPositioning(r.pos);
10563 st.width = r.width;
10564 st.height = r.height;
10569 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10570 this.clearOpacity();
10574 points:{by:[0, this.getHeight() * .5]}
10575 }, o, 'motion', 0.3, 'easeIn', after);
10576 }).defer(100, this);
10583 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10584 * changed using the "attr" config option) and then fading back to the original color. If no original
10585 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10588 // default: highlight background to yellow
10591 // custom: highlight foreground text to blue for 2 seconds
10592 el.highlight("0000ff", { attr: 'color', duration: 2 });
10594 // common config options shown with default values
10595 el.highlight("ffff9c", {
10596 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10597 endColor: (current color) or "ffffff",
10602 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10603 * @param {Object} options (optional) Object literal with any of the Fx config options
10604 * @return {Roo.Element} The Element
10606 highlight : function(color, o){
10607 var el = this.getFxEl();
10610 el.queueFx(o, function(){
10611 color = color || "ffff9c";
10612 attr = o.attr || "backgroundColor";
10614 this.clearOpacity();
10617 var origColor = this.getColor(attr);
10618 var restoreColor = this.dom.style[attr];
10619 endColor = (o.endColor || origColor) || "ffffff";
10621 var after = function(){
10622 el.dom.style[attr] = restoreColor;
10627 a[attr] = {from: color, to: endColor};
10628 arguments.callee.anim = this.fxanim(a,
10638 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10641 // default: a single light blue ripple
10644 // custom: 3 red ripples lasting 3 seconds total
10645 el.frame("ff0000", 3, { duration: 3 });
10647 // common config options shown with default values
10648 el.frame("C3DAF9", 1, {
10649 duration: 1 //duration of entire animation (not each individual ripple)
10650 // Note: Easing is not configurable and will be ignored if included
10653 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10654 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10655 * @param {Object} options (optional) Object literal with any of the Fx config options
10656 * @return {Roo.Element} The Element
10658 frame : function(color, count, o){
10659 var el = this.getFxEl();
10662 el.queueFx(o, function(){
10663 color = color || "#C3DAF9";
10664 if(color.length == 6){
10665 color = "#" + color;
10667 count = count || 1;
10668 duration = o.duration || 1;
10671 var b = this.getBox();
10672 var animFn = function(){
10673 var proxy = this.createProxy({
10676 visbility:"hidden",
10677 position:"absolute",
10678 "z-index":"35000", // yee haw
10679 border:"0px solid " + color
10682 var scale = Roo.isBorderBox ? 2 : 1;
10684 top:{from:b.y, to:b.y - 20},
10685 left:{from:b.x, to:b.x - 20},
10686 borderWidth:{from:0, to:10},
10687 opacity:{from:1, to:0},
10688 height:{from:b.height, to:(b.height + (20*scale))},
10689 width:{from:b.width, to:(b.width + (20*scale))}
10690 }, duration, function(){
10694 animFn.defer((duration/2)*1000, this);
10705 * Creates a pause before any subsequent queued effects begin. If there are
10706 * no effects queued after the pause it will have no effect.
10711 * @param {Number} seconds The length of time to pause (in seconds)
10712 * @return {Roo.Element} The Element
10714 pause : function(seconds){
10715 var el = this.getFxEl();
10718 el.queueFx(o, function(){
10719 setTimeout(function(){
10721 }, seconds * 1000);
10727 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10728 * using the "endOpacity" config option.
10731 // default: fade in from opacity 0 to 100%
10734 // custom: fade in from opacity 0 to 75% over 2 seconds
10735 el.fadeIn({ endOpacity: .75, duration: 2});
10737 // common config options shown with default values
10739 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10744 * @param {Object} options (optional) Object literal with any of the Fx config options
10745 * @return {Roo.Element} The Element
10747 fadeIn : function(o){
10748 var el = this.getFxEl();
10750 el.queueFx(o, function(){
10751 this.setOpacity(0);
10753 this.dom.style.visibility = 'visible';
10754 var to = o.endOpacity || 1;
10755 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10756 o, null, .5, "easeOut", function(){
10758 this.clearOpacity();
10767 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10768 * using the "endOpacity" config option.
10771 // default: fade out from the element's current opacity to 0
10774 // custom: fade out from the element's current opacity to 25% over 2 seconds
10775 el.fadeOut({ endOpacity: .25, duration: 2});
10777 // common config options shown with default values
10779 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10786 * @param {Object} options (optional) Object literal with any of the Fx config options
10787 * @return {Roo.Element} The Element
10789 fadeOut : function(o){
10790 var el = this.getFxEl();
10792 el.queueFx(o, function(){
10793 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10794 o, null, .5, "easeOut", function(){
10795 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10796 this.dom.style.display = "none";
10798 this.dom.style.visibility = "hidden";
10800 this.clearOpacity();
10808 * Animates the transition of an element's dimensions from a starting height/width
10809 * to an ending height/width.
10812 // change height and width to 100x100 pixels
10813 el.scale(100, 100);
10815 // common config options shown with default values. The height and width will default to
10816 // the element's existing values if passed as null.
10819 [element's height], {
10824 * @param {Number} width The new width (pass undefined to keep the original width)
10825 * @param {Number} height The new height (pass undefined to keep the original height)
10826 * @param {Object} options (optional) Object literal with any of the Fx config options
10827 * @return {Roo.Element} The Element
10829 scale : function(w, h, o){
10830 this.shift(Roo.apply({}, o, {
10838 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10839 * Any of these properties not specified in the config object will not be changed. This effect
10840 * requires that at least one new dimension, position or opacity setting must be passed in on
10841 * the config object in order for the function to have any effect.
10844 // slide the element horizontally to x position 200 while changing the height and opacity
10845 el.shift({ x: 200, height: 50, opacity: .8 });
10847 // common config options shown with default values.
10849 width: [element's width],
10850 height: [element's height],
10851 x: [element's x position],
10852 y: [element's y position],
10853 opacity: [element's opacity],
10858 * @param {Object} options Object literal with any of the Fx config options
10859 * @return {Roo.Element} The Element
10861 shift : function(o){
10862 var el = this.getFxEl();
10864 el.queueFx(o, function(){
10865 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10866 if(w !== undefined){
10867 a.width = {to: this.adjustWidth(w)};
10869 if(h !== undefined){
10870 a.height = {to: this.adjustHeight(h)};
10872 if(x !== undefined || y !== undefined){
10874 x !== undefined ? x : this.getX(),
10875 y !== undefined ? y : this.getY()
10878 if(op !== undefined){
10879 a.opacity = {to: op};
10881 if(o.xy !== undefined){
10882 a.points = {to: o.xy};
10884 arguments.callee.anim = this.fxanim(a,
10885 o, 'motion', .35, "easeOut", function(){
10893 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10894 * ending point of the effect.
10897 // default: slide the element downward while fading out
10900 // custom: slide the element out to the right with a 2-second duration
10901 el.ghost('r', { duration: 2 });
10903 // common config options shown with default values
10911 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10912 * @param {Object} options (optional) Object literal with any of the Fx config options
10913 * @return {Roo.Element} The Element
10915 ghost : function(anchor, o){
10916 var el = this.getFxEl();
10919 el.queueFx(o, function(){
10920 anchor = anchor || "b";
10922 // restore values after effect
10923 var r = this.getFxRestore();
10924 var w = this.getWidth(),
10925 h = this.getHeight();
10927 var st = this.dom.style;
10929 var after = function(){
10931 el.setDisplayed(false);
10937 el.setPositioning(r.pos);
10938 st.width = r.width;
10939 st.height = r.height;
10944 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10945 switch(anchor.toLowerCase()){
10972 arguments.callee.anim = this.fxanim(a,
10982 * Ensures that all effects queued after syncFx is called on the element are
10983 * run concurrently. This is the opposite of {@link #sequenceFx}.
10984 * @return {Roo.Element} The Element
10986 syncFx : function(){
10987 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10996 * Ensures that all effects queued after sequenceFx is called on the element are
10997 * run in sequence. This is the opposite of {@link #syncFx}.
10998 * @return {Roo.Element} The Element
11000 sequenceFx : function(){
11001 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11003 concurrent : false,
11010 nextFx : function(){
11011 var ef = this.fxQueue[0];
11018 * Returns true if the element has any effects actively running or queued, else returns false.
11019 * @return {Boolean} True if element has active effects, else false
11021 hasActiveFx : function(){
11022 return this.fxQueue && this.fxQueue[0];
11026 * Stops any running effects and clears the element's internal effects queue if it contains
11027 * any additional effects that haven't started yet.
11028 * @return {Roo.Element} The Element
11030 stopFx : function(){
11031 if(this.hasActiveFx()){
11032 var cur = this.fxQueue[0];
11033 if(cur && cur.anim && cur.anim.isAnimated()){
11034 this.fxQueue = [cur]; // clear out others
11035 cur.anim.stop(true);
11042 beforeFx : function(o){
11043 if(this.hasActiveFx() && !o.concurrent){
11054 * Returns true if the element is currently blocking so that no other effect can be queued
11055 * until this effect is finished, else returns false if blocking is not set. This is commonly
11056 * used to ensure that an effect initiated by a user action runs to completion prior to the
11057 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11058 * @return {Boolean} True if blocking, else false
11060 hasFxBlock : function(){
11061 var q = this.fxQueue;
11062 return q && q[0] && q[0].block;
11066 queueFx : function(o, fn){
11070 if(!this.hasFxBlock()){
11071 Roo.applyIf(o, this.fxDefaults);
11073 var run = this.beforeFx(o);
11074 fn.block = o.block;
11075 this.fxQueue.push(fn);
11087 fxWrap : function(pos, o, vis){
11089 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11092 wrapXY = this.getXY();
11094 var div = document.createElement("div");
11095 div.style.visibility = vis;
11096 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11097 wrap.setPositioning(pos);
11098 if(wrap.getStyle("position") == "static"){
11099 wrap.position("relative");
11101 this.clearPositioning('auto');
11103 wrap.dom.appendChild(this.dom);
11105 wrap.setXY(wrapXY);
11112 fxUnwrap : function(wrap, pos, o){
11113 this.clearPositioning();
11114 this.setPositioning(pos);
11116 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11122 getFxRestore : function(){
11123 var st = this.dom.style;
11124 return {pos: this.getPositioning(), width: st.width, height : st.height};
11128 afterFx : function(o){
11130 this.applyStyles(o.afterStyle);
11133 this.addClass(o.afterCls);
11135 if(o.remove === true){
11138 Roo.callback(o.callback, o.scope, [this]);
11140 this.fxQueue.shift();
11146 getFxEl : function(){ // support for composite element fx
11147 return Roo.get(this.dom);
11151 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11152 animType = animType || 'run';
11154 var anim = Roo.lib.Anim[animType](
11156 (opt.duration || defaultDur) || .35,
11157 (opt.easing || defaultEase) || 'easeOut',
11159 Roo.callback(cb, this);
11168 // backwords compat
11169 Roo.Fx.resize = Roo.Fx.scale;
11171 //When included, Roo.Fx is automatically applied to Element so that all basic
11172 //effects are available directly via the Element API
11173 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11175 * Ext JS Library 1.1.1
11176 * Copyright(c) 2006-2007, Ext JS, LLC.
11178 * Originally Released Under LGPL - original licence link has changed is not relivant.
11181 * <script type="text/javascript">
11186 * @class Roo.CompositeElement
11187 * Standard composite class. Creates a Roo.Element for every element in the collection.
11189 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11190 * actions will be performed on all the elements in this collection.</b>
11192 * All methods return <i>this</i> and can be chained.
11194 var els = Roo.select("#some-el div.some-class", true);
11195 // or select directly from an existing element
11196 var el = Roo.get('some-el');
11197 el.select('div.some-class', true);
11199 els.setWidth(100); // all elements become 100 width
11200 els.hide(true); // all elements fade out and hide
11202 els.setWidth(100).hide(true);
11205 Roo.CompositeElement = function(els){
11206 this.elements = [];
11207 this.addElements(els);
11209 Roo.CompositeElement.prototype = {
11211 addElements : function(els){
11215 if(typeof els == "string"){
11216 els = Roo.Element.selectorFunction(els);
11218 var yels = this.elements;
11219 var index = yels.length-1;
11220 for(var i = 0, len = els.length; i < len; i++) {
11221 yels[++index] = Roo.get(els[i]);
11227 * Clears this composite and adds the elements returned by the passed selector.
11228 * @param {String/Array} els A string CSS selector, an array of elements or an element
11229 * @return {CompositeElement} this
11231 fill : function(els){
11232 this.elements = [];
11238 * Filters this composite to only elements that match the passed selector.
11239 * @param {String} selector A string CSS selector
11240 * @param {Boolean} inverse return inverse filter (not matches)
11241 * @return {CompositeElement} this
11243 filter : function(selector, inverse){
11245 inverse = inverse || false;
11246 this.each(function(el){
11247 var match = inverse ? !el.is(selector) : el.is(selector);
11249 els[els.length] = el.dom;
11256 invoke : function(fn, args){
11257 var els = this.elements;
11258 for(var i = 0, len = els.length; i < len; i++) {
11259 Roo.Element.prototype[fn].apply(els[i], args);
11264 * Adds elements to this composite.
11265 * @param {String/Array} els A string CSS selector, an array of elements or an element
11266 * @return {CompositeElement} this
11268 add : function(els){
11269 if(typeof els == "string"){
11270 this.addElements(Roo.Element.selectorFunction(els));
11271 }else if(els.length !== undefined){
11272 this.addElements(els);
11274 this.addElements([els]);
11279 * Calls the passed function passing (el, this, index) for each element in this composite.
11280 * @param {Function} fn The function to call
11281 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11282 * @return {CompositeElement} this
11284 each : function(fn, scope){
11285 var els = this.elements;
11286 for(var i = 0, len = els.length; i < len; i++){
11287 if(fn.call(scope || els[i], els[i], this, i) === false) {
11295 * Returns the Element object at the specified index
11296 * @param {Number} index
11297 * @return {Roo.Element}
11299 item : function(index){
11300 return this.elements[index] || null;
11304 * Returns the first Element
11305 * @return {Roo.Element}
11307 first : function(){
11308 return this.item(0);
11312 * Returns the last Element
11313 * @return {Roo.Element}
11316 return this.item(this.elements.length-1);
11320 * Returns the number of elements in this composite
11323 getCount : function(){
11324 return this.elements.length;
11328 * Returns true if this composite contains the passed element
11331 contains : function(el){
11332 return this.indexOf(el) !== -1;
11336 * Returns true if this composite contains the passed element
11339 indexOf : function(el){
11340 return this.elements.indexOf(Roo.get(el));
11345 * Removes the specified element(s).
11346 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11347 * or an array of any of those.
11348 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11349 * @return {CompositeElement} this
11351 removeElement : function(el, removeDom){
11352 if(el instanceof Array){
11353 for(var i = 0, len = el.length; i < len; i++){
11354 this.removeElement(el[i]);
11358 var index = typeof el == 'number' ? el : this.indexOf(el);
11361 var d = this.elements[index];
11365 d.parentNode.removeChild(d);
11368 this.elements.splice(index, 1);
11374 * Replaces the specified element with the passed element.
11375 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11377 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11378 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11379 * @return {CompositeElement} this
11381 replaceElement : function(el, replacement, domReplace){
11382 var index = typeof el == 'number' ? el : this.indexOf(el);
11385 this.elements[index].replaceWith(replacement);
11387 this.elements.splice(index, 1, Roo.get(replacement))
11394 * Removes all elements.
11396 clear : function(){
11397 this.elements = [];
11401 Roo.CompositeElement.createCall = function(proto, fnName){
11402 if(!proto[fnName]){
11403 proto[fnName] = function(){
11404 return this.invoke(fnName, arguments);
11408 for(var fnName in Roo.Element.prototype){
11409 if(typeof Roo.Element.prototype[fnName] == "function"){
11410 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11416 * Ext JS Library 1.1.1
11417 * Copyright(c) 2006-2007, Ext JS, LLC.
11419 * Originally Released Under LGPL - original licence link has changed is not relivant.
11422 * <script type="text/javascript">
11426 * @class Roo.CompositeElementLite
11427 * @extends Roo.CompositeElement
11428 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11430 var els = Roo.select("#some-el div.some-class");
11431 // or select directly from an existing element
11432 var el = Roo.get('some-el');
11433 el.select('div.some-class');
11435 els.setWidth(100); // all elements become 100 width
11436 els.hide(true); // all elements fade out and hide
11438 els.setWidth(100).hide(true);
11439 </code></pre><br><br>
11440 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11441 * actions will be performed on all the elements in this collection.</b>
11443 Roo.CompositeElementLite = function(els){
11444 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11445 this.el = new Roo.Element.Flyweight();
11447 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11448 addElements : function(els){
11450 if(els instanceof Array){
11451 this.elements = this.elements.concat(els);
11453 var yels = this.elements;
11454 var index = yels.length-1;
11455 for(var i = 0, len = els.length; i < len; i++) {
11456 yels[++index] = els[i];
11462 invoke : function(fn, args){
11463 var els = this.elements;
11465 for(var i = 0, len = els.length; i < len; i++) {
11467 Roo.Element.prototype[fn].apply(el, args);
11472 * Returns a flyweight Element of the dom element object at the specified index
11473 * @param {Number} index
11474 * @return {Roo.Element}
11476 item : function(index){
11477 if(!this.elements[index]){
11480 this.el.dom = this.elements[index];
11484 // fixes scope with flyweight
11485 addListener : function(eventName, handler, scope, opt){
11486 var els = this.elements;
11487 for(var i = 0, len = els.length; i < len; i++) {
11488 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11494 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11495 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11496 * a reference to the dom node, use el.dom.</b>
11497 * @param {Function} fn The function to call
11498 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11499 * @return {CompositeElement} this
11501 each : function(fn, scope){
11502 var els = this.elements;
11504 for(var i = 0, len = els.length; i < len; i++){
11506 if(fn.call(scope || el, el, this, i) === false){
11513 indexOf : function(el){
11514 return this.elements.indexOf(Roo.getDom(el));
11517 replaceElement : function(el, replacement, domReplace){
11518 var index = typeof el == 'number' ? el : this.indexOf(el);
11520 replacement = Roo.getDom(replacement);
11522 var d = this.elements[index];
11523 d.parentNode.insertBefore(replacement, d);
11524 d.parentNode.removeChild(d);
11526 this.elements.splice(index, 1, replacement);
11531 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11535 * Ext JS Library 1.1.1
11536 * Copyright(c) 2006-2007, Ext JS, LLC.
11538 * Originally Released Under LGPL - original licence link has changed is not relivant.
11541 * <script type="text/javascript">
11547 * @class Roo.data.Connection
11548 * @extends Roo.util.Observable
11549 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11550 * either to a configured URL, or to a URL specified at request time.
11552 * Requests made by this class are asynchronous, and will return immediately. No data from
11553 * the server will be available to the statement immediately following the {@link #request} call.
11554 * To process returned data, use a callback in the request options object, or an event listener.
11556 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11557 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11558 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11559 * property and, if present, the IFRAME's XML document as the responseXML property.
11561 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11562 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11563 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11564 * standard DOM methods.
11566 * @param {Object} config a configuration object.
11568 Roo.data.Connection = function(config){
11569 Roo.apply(this, config);
11572 * @event beforerequest
11573 * Fires before a network request is made to retrieve a data object.
11574 * @param {Connection} conn This Connection object.
11575 * @param {Object} options The options config object passed to the {@link #request} method.
11577 "beforerequest" : true,
11579 * @event requestcomplete
11580 * Fires if the request was successfully completed.
11581 * @param {Connection} conn This Connection object.
11582 * @param {Object} response The XHR object containing the response data.
11583 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11584 * @param {Object} options The options config object passed to the {@link #request} method.
11586 "requestcomplete" : true,
11588 * @event requestexception
11589 * Fires if an error HTTP status was returned from the server.
11590 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11591 * @param {Connection} conn This Connection object.
11592 * @param {Object} response The XHR object containing the response data.
11593 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11594 * @param {Object} options The options config object passed to the {@link #request} method.
11596 "requestexception" : true
11598 Roo.data.Connection.superclass.constructor.call(this);
11601 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11603 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11606 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11607 * extra parameters to each request made by this object. (defaults to undefined)
11610 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11611 * to each request made by this object. (defaults to undefined)
11614 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11617 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11621 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11627 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11630 disableCaching: true,
11633 * Sends an HTTP request to a remote server.
11634 * @param {Object} options An object which may contain the following properties:<ul>
11635 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11636 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11637 * request, a url encoded string or a function to call to get either.</li>
11638 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11639 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11640 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11641 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11642 * <li>options {Object} The parameter to the request call.</li>
11643 * <li>success {Boolean} True if the request succeeded.</li>
11644 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11646 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11647 * The callback is passed the following parameters:<ul>
11648 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11649 * <li>options {Object} The parameter to the request call.</li>
11651 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11652 * The callback is passed the following parameters:<ul>
11653 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11654 * <li>options {Object} The parameter to the request call.</li>
11656 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11657 * for the callback function. Defaults to the browser window.</li>
11658 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11659 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11660 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11661 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11662 * params for the post data. Any params will be appended to the URL.</li>
11663 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11665 * @return {Number} transactionId
11667 request : function(o){
11668 if(this.fireEvent("beforerequest", this, o) !== false){
11671 if(typeof p == "function"){
11672 p = p.call(o.scope||window, o);
11674 if(typeof p == "object"){
11675 p = Roo.urlEncode(o.params);
11677 if(this.extraParams){
11678 var extras = Roo.urlEncode(this.extraParams);
11679 p = p ? (p + '&' + extras) : extras;
11682 var url = o.url || this.url;
11683 if(typeof url == 'function'){
11684 url = url.call(o.scope||window, o);
11688 var form = Roo.getDom(o.form);
11689 url = url || form.action;
11691 var enctype = form.getAttribute("enctype");
11694 return this.doFormDataUpload(o, url);
11697 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11698 return this.doFormUpload(o, p, url);
11700 var f = Roo.lib.Ajax.serializeForm(form);
11701 p = p ? (p + '&' + f) : f;
11704 if (!o.form && o.formData) {
11705 o.formData = o.formData === true ? new FormData() : o.formData;
11706 for (var k in o.params) {
11707 o.formData.append(k,o.params[k]);
11710 return this.doFormDataUpload(o, url);
11714 var hs = o.headers;
11715 if(this.defaultHeaders){
11716 hs = Roo.apply(hs || {}, this.defaultHeaders);
11723 success: this.handleResponse,
11724 failure: this.handleFailure,
11726 argument: {options: o},
11727 timeout : o.timeout || this.timeout
11730 var method = o.method||this.method||(p ? "POST" : "GET");
11732 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11733 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11736 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11740 }else if(this.autoAbort !== false){
11744 if((method == 'GET' && p) || o.xmlData){
11745 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11748 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11749 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11750 Roo.lib.Ajax.useDefaultHeader == true;
11751 return this.transId;
11753 Roo.callback(o.callback, o.scope, [o, null, null]);
11759 * Determine whether this object has a request outstanding.
11760 * @param {Number} transactionId (Optional) defaults to the last transaction
11761 * @return {Boolean} True if there is an outstanding request.
11763 isLoading : function(transId){
11765 return Roo.lib.Ajax.isCallInProgress(transId);
11767 return this.transId ? true : false;
11772 * Aborts any outstanding request.
11773 * @param {Number} transactionId (Optional) defaults to the last transaction
11775 abort : function(transId){
11776 if(transId || this.isLoading()){
11777 Roo.lib.Ajax.abort(transId || this.transId);
11782 handleResponse : function(response){
11783 this.transId = false;
11784 var options = response.argument.options;
11785 response.argument = options ? options.argument : null;
11786 this.fireEvent("requestcomplete", this, response, options);
11787 Roo.callback(options.success, options.scope, [response, options]);
11788 Roo.callback(options.callback, options.scope, [options, true, response]);
11792 handleFailure : function(response, e){
11793 this.transId = false;
11794 var options = response.argument.options;
11795 response.argument = options ? options.argument : null;
11796 this.fireEvent("requestexception", this, response, options, e);
11797 Roo.callback(options.failure, options.scope, [response, options]);
11798 Roo.callback(options.callback, options.scope, [options, false, response]);
11802 doFormUpload : function(o, ps, url){
11804 var frame = document.createElement('iframe');
11807 frame.className = 'x-hidden';
11809 frame.src = Roo.SSL_SECURE_URL;
11811 document.body.appendChild(frame);
11814 document.frames[id].name = id;
11817 var form = Roo.getDom(o.form);
11819 form.method = 'POST';
11820 form.enctype = form.encoding = 'multipart/form-data';
11826 if(ps){ // add dynamic params
11828 ps = Roo.urlDecode(ps, false);
11830 if(ps.hasOwnProperty(k)){
11831 hd = document.createElement('input');
11832 hd.type = 'hidden';
11835 form.appendChild(hd);
11842 var r = { // bogus response object
11847 r.argument = o ? o.argument : null;
11852 doc = frame.contentWindow.document;
11854 doc = (frame.contentDocument || window.frames[id].document);
11856 if(doc && doc.body){
11857 r.responseText = doc.body.innerHTML;
11859 if(doc && doc.XMLDocument){
11860 r.responseXML = doc.XMLDocument;
11862 r.responseXML = doc;
11869 Roo.EventManager.removeListener(frame, 'load', cb, this);
11871 this.fireEvent("requestcomplete", this, r, o);
11872 Roo.callback(o.success, o.scope, [r, o]);
11873 Roo.callback(o.callback, o.scope, [o, true, r]);
11875 setTimeout(function(){document.body.removeChild(frame);}, 100);
11878 Roo.EventManager.on(frame, 'load', cb, this);
11881 if(hiddens){ // remove dynamic params
11882 for(var i = 0, len = hiddens.length; i < len; i++){
11883 form.removeChild(hiddens[i]);
11887 // this is a 'formdata version???'
11890 doFormDataUpload : function(o, url)
11894 var form = Roo.getDom(o.form);
11895 form.enctype = form.encoding = 'multipart/form-data';
11896 formData = o.formData === true ? new FormData(form) : o.formData;
11898 formData = o.formData === true ? new FormData() : o.formData;
11903 success: this.handleResponse,
11904 failure: this.handleFailure,
11906 argument: {options: o},
11907 timeout : o.timeout || this.timeout
11910 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11914 }else if(this.autoAbort !== false){
11918 //Roo.lib.Ajax.defaultPostHeader = null;
11919 Roo.lib.Ajax.useDefaultHeader = false;
11920 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11921 Roo.lib.Ajax.useDefaultHeader = true;
11929 * Ext JS Library 1.1.1
11930 * Copyright(c) 2006-2007, Ext JS, LLC.
11932 * Originally Released Under LGPL - original licence link has changed is not relivant.
11935 * <script type="text/javascript">
11939 * Global Ajax request class.
11942 * @extends Roo.data.Connection
11945 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11946 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11947 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11948 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11949 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11950 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11951 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11953 Roo.Ajax = new Roo.data.Connection({
11962 * Serialize the passed form into a url encoded string
11964 * @param {String/HTMLElement} form
11967 serializeForm : function(form){
11968 return Roo.lib.Ajax.serializeForm(form);
11972 * Ext JS Library 1.1.1
11973 * Copyright(c) 2006-2007, Ext JS, LLC.
11975 * Originally Released Under LGPL - original licence link has changed is not relivant.
11978 * <script type="text/javascript">
11983 * @class Roo.UpdateManager
11984 * @extends Roo.util.Observable
11985 * Provides AJAX-style update for Element object.<br><br>
11988 * // Get it from a Roo.Element object
11989 * var el = Roo.get("foo");
11990 * var mgr = el.getUpdateManager();
11991 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11993 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11995 * // or directly (returns the same UpdateManager instance)
11996 * var mgr = new Roo.UpdateManager("myElementId");
11997 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11998 * mgr.on("update", myFcnNeedsToKnow);
12000 // short handed call directly from the element object
12001 Roo.get("foo").load({
12005 text: "Loading Foo..."
12009 * Create new UpdateManager directly.
12010 * @param {String/HTMLElement/Roo.Element} el The element to update
12011 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
12013 Roo.UpdateManager = function(el, forceNew){
12015 if(!forceNew && el.updateManager){
12016 return el.updateManager;
12019 * The Element object
12020 * @type Roo.Element
12024 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12027 this.defaultUrl = null;
12031 * @event beforeupdate
12032 * Fired before an update is made, return false from your handler and the update is cancelled.
12033 * @param {Roo.Element} el
12034 * @param {String/Object/Function} url
12035 * @param {String/Object} params
12037 "beforeupdate": true,
12040 * Fired after successful update is made.
12041 * @param {Roo.Element} el
12042 * @param {Object} oResponseObject The response Object
12047 * Fired on update failure.
12048 * @param {Roo.Element} el
12049 * @param {Object} oResponseObject The response Object
12053 var d = Roo.UpdateManager.defaults;
12055 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12058 this.sslBlankUrl = d.sslBlankUrl;
12060 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12063 this.disableCaching = d.disableCaching;
12065 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12068 this.indicatorText = d.indicatorText;
12070 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12073 this.showLoadIndicator = d.showLoadIndicator;
12075 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12078 this.timeout = d.timeout;
12081 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12084 this.loadScripts = d.loadScripts;
12087 * Transaction object of current executing transaction
12089 this.transaction = null;
12094 this.autoRefreshProcId = null;
12096 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12099 this.refreshDelegate = this.refresh.createDelegate(this);
12101 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12104 this.updateDelegate = this.update.createDelegate(this);
12106 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12109 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12113 this.successDelegate = this.processSuccess.createDelegate(this);
12117 this.failureDelegate = this.processFailure.createDelegate(this);
12119 if(!this.renderer){
12121 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12123 this.renderer = new Roo.UpdateManager.BasicRenderer();
12126 Roo.UpdateManager.superclass.constructor.call(this);
12129 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12131 * Get the Element this UpdateManager is bound to
12132 * @return {Roo.Element} The element
12134 getEl : function(){
12138 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12139 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
12142 url: "your-url.php",<br/>
12143 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12144 callback: yourFunction,<br/>
12145 scope: yourObject, //(optional scope) <br/>
12146 discardUrl: false, <br/>
12147 nocache: false,<br/>
12148 text: "Loading...",<br/>
12150 scripts: false<br/>
12153 * The only required property is url. The optional properties nocache, text and scripts
12154 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12155 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
12156 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12157 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
12159 update : function(url, params, callback, discardUrl){
12160 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12161 var method = this.method,
12163 if(typeof url == "object"){ // must be config object
12166 params = params || cfg.params;
12167 callback = callback || cfg.callback;
12168 discardUrl = discardUrl || cfg.discardUrl;
12169 if(callback && cfg.scope){
12170 callback = callback.createDelegate(cfg.scope);
12172 if(typeof cfg.method != "undefined"){method = cfg.method;};
12173 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12174 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12175 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12176 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12178 this.showLoading();
12180 this.defaultUrl = url;
12182 if(typeof url == "function"){
12183 url = url.call(this);
12186 method = method || (params ? "POST" : "GET");
12187 if(method == "GET"){
12188 url = this.prepareUrl(url);
12191 var o = Roo.apply(cfg ||{}, {
12194 success: this.successDelegate,
12195 failure: this.failureDelegate,
12196 callback: undefined,
12197 timeout: (this.timeout*1000),
12198 argument: {"url": url, "form": null, "callback": callback, "params": params}
12200 Roo.log("updated manager called with timeout of " + o.timeout);
12201 this.transaction = Roo.Ajax.request(o);
12206 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
12207 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12208 * @param {String/HTMLElement} form The form Id or form element
12209 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12210 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12211 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12213 formUpdate : function(form, url, reset, callback){
12214 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12215 if(typeof url == "function"){
12216 url = url.call(this);
12218 form = Roo.getDom(form);
12219 this.transaction = Roo.Ajax.request({
12222 success: this.successDelegate,
12223 failure: this.failureDelegate,
12224 timeout: (this.timeout*1000),
12225 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12227 this.showLoading.defer(1, this);
12232 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12233 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12235 refresh : function(callback){
12236 if(this.defaultUrl == null){
12239 this.update(this.defaultUrl, null, callback, true);
12243 * Set this element to auto refresh.
12244 * @param {Number} interval How often to update (in seconds).
12245 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
12246 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
12247 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12248 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12250 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12252 this.update(url || this.defaultUrl, params, callback, true);
12254 if(this.autoRefreshProcId){
12255 clearInterval(this.autoRefreshProcId);
12257 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12261 * Stop auto refresh on this element.
12263 stopAutoRefresh : function(){
12264 if(this.autoRefreshProcId){
12265 clearInterval(this.autoRefreshProcId);
12266 delete this.autoRefreshProcId;
12270 isAutoRefreshing : function(){
12271 return this.autoRefreshProcId ? true : false;
12274 * Called to update the element to "Loading" state. Override to perform custom action.
12276 showLoading : function(){
12277 if(this.showLoadIndicator){
12278 this.el.update(this.indicatorText);
12283 * Adds unique parameter to query string if disableCaching = true
12286 prepareUrl : function(url){
12287 if(this.disableCaching){
12288 var append = "_dc=" + (new Date().getTime());
12289 if(url.indexOf("?") !== -1){
12290 url += "&" + append;
12292 url += "?" + append;
12301 processSuccess : function(response){
12302 this.transaction = null;
12303 if(response.argument.form && response.argument.reset){
12304 try{ // put in try/catch since some older FF releases had problems with this
12305 response.argument.form.reset();
12308 if(this.loadScripts){
12309 this.renderer.render(this.el, response, this,
12310 this.updateComplete.createDelegate(this, [response]));
12312 this.renderer.render(this.el, response, this);
12313 this.updateComplete(response);
12317 updateComplete : function(response){
12318 this.fireEvent("update", this.el, response);
12319 if(typeof response.argument.callback == "function"){
12320 response.argument.callback(this.el, true, response);
12327 processFailure : function(response){
12328 this.transaction = null;
12329 this.fireEvent("failure", this.el, response);
12330 if(typeof response.argument.callback == "function"){
12331 response.argument.callback(this.el, false, response);
12336 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12337 * @param {Object} renderer The object implementing the render() method
12339 setRenderer : function(renderer){
12340 this.renderer = renderer;
12343 getRenderer : function(){
12344 return this.renderer;
12348 * Set the defaultUrl used for updates
12349 * @param {String/Function} defaultUrl The url or a function to call to get the url
12351 setDefaultUrl : function(defaultUrl){
12352 this.defaultUrl = defaultUrl;
12356 * Aborts the executing transaction
12358 abort : function(){
12359 if(this.transaction){
12360 Roo.Ajax.abort(this.transaction);
12365 * Returns true if an update is in progress
12366 * @return {Boolean}
12368 isUpdating : function(){
12369 if(this.transaction){
12370 return Roo.Ajax.isLoading(this.transaction);
12377 * @class Roo.UpdateManager.defaults
12378 * @static (not really - but it helps the doc tool)
12379 * The defaults collection enables customizing the default properties of UpdateManager
12381 Roo.UpdateManager.defaults = {
12383 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12389 * True to process scripts by default (Defaults to false).
12392 loadScripts : false,
12395 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12398 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12400 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12403 disableCaching : false,
12405 * Whether to show indicatorText when loading (Defaults to true).
12408 showLoadIndicator : true,
12410 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12413 indicatorText : '<div class="loading-indicator">Loading...</div>'
12417 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12419 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12420 * @param {String/HTMLElement/Roo.Element} el The element to update
12421 * @param {String} url The url
12422 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12423 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12426 * @member Roo.UpdateManager
12428 Roo.UpdateManager.updateElement = function(el, url, params, options){
12429 var um = Roo.get(el, true).getUpdateManager();
12430 Roo.apply(um, options);
12431 um.update(url, params, options ? options.callback : null);
12433 // alias for backwards compat
12434 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12436 * @class Roo.UpdateManager.BasicRenderer
12437 * Default Content renderer. Updates the elements innerHTML with the responseText.
12439 Roo.UpdateManager.BasicRenderer = function(){};
12441 Roo.UpdateManager.BasicRenderer.prototype = {
12443 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12444 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12445 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12446 * @param {Roo.Element} el The element being rendered
12447 * @param {Object} response The YUI Connect response object
12448 * @param {UpdateManager} updateManager The calling update manager
12449 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12451 render : function(el, response, updateManager, callback){
12452 el.update(response.responseText, updateManager.loadScripts, callback);
12458 * (c)) Alan Knowles
12464 * @class Roo.DomTemplate
12465 * @extends Roo.Template
12466 * An effort at a dom based template engine..
12468 * Similar to XTemplate, except it uses dom parsing to create the template..
12470 * Supported features:
12475 {a_variable} - output encoded.
12476 {a_variable.format:("Y-m-d")} - call a method on the variable
12477 {a_variable:raw} - unencoded output
12478 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12479 {a_variable:this.method_on_template(...)} - call a method on the template object.
12484 <div roo-for="a_variable or condition.."></div>
12485 <div roo-if="a_variable or condition"></div>
12486 <div roo-exec="some javascript"></div>
12487 <div roo-name="named_template"></div>
12492 Roo.DomTemplate = function()
12494 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12501 Roo.extend(Roo.DomTemplate, Roo.Template, {
12503 * id counter for sub templates.
12507 * flag to indicate if dom parser is inside a pre,
12508 * it will strip whitespace if not.
12513 * The various sub templates
12521 * basic tag replacing syntax
12524 * // you can fake an object call by doing this
12528 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12529 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12531 iterChild : function (node, method) {
12533 var oldPre = this.inPre;
12534 if (node.tagName == 'PRE') {
12537 for( var i = 0; i < node.childNodes.length; i++) {
12538 method.call(this, node.childNodes[i]);
12540 this.inPre = oldPre;
12546 * compile the template
12548 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12551 compile: function()
12555 // covert the html into DOM...
12559 doc = document.implementation.createHTMLDocument("");
12560 doc.documentElement.innerHTML = this.html ;
12561 div = doc.documentElement;
12563 // old IE... - nasty -- it causes all sorts of issues.. with
12564 // images getting pulled from server..
12565 div = document.createElement('div');
12566 div.innerHTML = this.html;
12568 //doc.documentElement.innerHTML = htmlBody
12574 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12576 var tpls = this.tpls;
12578 // create a top level template from the snippet..
12580 //Roo.log(div.innerHTML);
12587 body : div.innerHTML,
12600 Roo.each(tpls, function(tp){
12601 this.compileTpl(tp);
12602 this.tpls[tp.id] = tp;
12605 this.master = tpls[0];
12611 compileNode : function(node, istop) {
12616 // skip anything not a tag..
12617 if (node.nodeType != 1) {
12618 if (node.nodeType == 3 && !this.inPre) {
12619 // reduce white space..
12620 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12643 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12644 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12645 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12646 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12652 // just itterate children..
12653 this.iterChild(node,this.compileNode);
12656 tpl.uid = this.id++;
12657 tpl.value = node.getAttribute('roo-' + tpl.attr);
12658 node.removeAttribute('roo-'+ tpl.attr);
12659 if (tpl.attr != 'name') {
12660 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12661 node.parentNode.replaceChild(placeholder, node);
12664 var placeholder = document.createElement('span');
12665 placeholder.className = 'roo-tpl-' + tpl.value;
12666 node.parentNode.replaceChild(placeholder, node);
12669 // parent now sees '{domtplXXXX}
12670 this.iterChild(node,this.compileNode);
12672 // we should now have node body...
12673 var div = document.createElement('div');
12674 div.appendChild(node);
12676 // this has the unfortunate side effect of converting tagged attributes
12677 // eg. href="{...}" into %7C...%7D
12678 // this has been fixed by searching for those combo's although it's a bit hacky..
12681 tpl.body = div.innerHTML;
12688 switch (tpl.value) {
12689 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12690 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12691 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12696 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12700 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12704 tpl.id = tpl.value; // replace non characters???
12710 this.tpls.push(tpl);
12720 * Compile a segment of the template into a 'sub-template'
12726 compileTpl : function(tpl)
12728 var fm = Roo.util.Format;
12729 var useF = this.disableFormats !== true;
12731 var sep = Roo.isGecko ? "+\n" : ",\n";
12733 var undef = function(str) {
12734 Roo.debug && Roo.log("Property not found :" + str);
12738 //Roo.log(tpl.body);
12742 var fn = function(m, lbrace, name, format, args)
12745 //Roo.log(arguments);
12746 args = args ? args.replace(/\\'/g,"'") : args;
12747 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12748 if (typeof(format) == 'undefined') {
12749 format = 'htmlEncode';
12751 if (format == 'raw' ) {
12755 if(name.substr(0, 6) == 'domtpl'){
12756 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12759 // build an array of options to determine if value is undefined..
12761 // basically get 'xxxx.yyyy' then do
12762 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12763 // (function () { Roo.log("Property not found"); return ''; })() :
12768 Roo.each(name.split('.'), function(st) {
12769 lookfor += (lookfor.length ? '.': '') + st;
12770 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12773 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12776 if(format && useF){
12778 args = args ? ',' + args : "";
12780 if(format.substr(0, 5) != "this."){
12781 format = "fm." + format + '(';
12783 format = 'this.call("'+ format.substr(5) + '", ';
12787 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12790 if (args && args.length) {
12791 // called with xxyx.yuu:(test,test)
12793 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12795 // raw.. - :raw modifier..
12796 return "'"+ sep + udef_st + name + ")"+sep+"'";
12800 // branched to use + in gecko and [].join() in others
12802 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12803 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12806 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12807 body.push(tpl.body.replace(/(\r\n|\n)/g,
12808 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12809 body.push("'].join('');};};");
12810 body = body.join('');
12813 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12815 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12822 * same as applyTemplate, except it's done to one of the subTemplates
12823 * when using named templates, you can do:
12825 * var str = pl.applySubTemplate('your-name', values);
12828 * @param {Number} id of the template
12829 * @param {Object} values to apply to template
12830 * @param {Object} parent (normaly the instance of this object)
12832 applySubTemplate : function(id, values, parent)
12836 var t = this.tpls[id];
12840 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12841 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12845 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12852 if(t.execCall && t.execCall.call(this, values, parent)){
12856 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12862 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12863 parent = t.target ? values : parent;
12864 if(t.forCall && vs instanceof Array){
12866 for(var i = 0, len = vs.length; i < len; i++){
12868 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12870 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12872 //Roo.log(t.compiled);
12876 return buf.join('');
12879 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12884 return t.compiled.call(this, vs, parent);
12886 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12888 //Roo.log(t.compiled);
12896 applyTemplate : function(values){
12897 return this.master.compiled.call(this, values, {});
12898 //var s = this.subs;
12901 apply : function(){
12902 return this.applyTemplate.apply(this, arguments);
12907 Roo.DomTemplate.from = function(el){
12908 el = Roo.getDom(el);
12909 return new Roo.Domtemplate(el.value || el.innerHTML);
12912 * Ext JS Library 1.1.1
12913 * Copyright(c) 2006-2007, Ext JS, LLC.
12915 * Originally Released Under LGPL - original licence link has changed is not relivant.
12918 * <script type="text/javascript">
12922 * @class Roo.util.DelayedTask
12923 * Provides a convenient method of performing setTimeout where a new
12924 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12925 * You can use this class to buffer
12926 * the keypress events for a certain number of milliseconds, and perform only if they stop
12927 * for that amount of time.
12928 * @constructor The parameters to this constructor serve as defaults and are not required.
12929 * @param {Function} fn (optional) The default function to timeout
12930 * @param {Object} scope (optional) The default scope of that timeout
12931 * @param {Array} args (optional) The default Array of arguments
12933 Roo.util.DelayedTask = function(fn, scope, args){
12934 var id = null, d, t;
12936 var call = function(){
12937 var now = new Date().getTime();
12941 fn.apply(scope, args || []);
12945 * Cancels any pending timeout and queues a new one
12946 * @param {Number} delay The milliseconds to delay
12947 * @param {Function} newFn (optional) Overrides function passed to constructor
12948 * @param {Object} newScope (optional) Overrides scope passed to constructor
12949 * @param {Array} newArgs (optional) Overrides args passed to constructor
12951 this.delay = function(delay, newFn, newScope, newArgs){
12952 if(id && delay != d){
12956 t = new Date().getTime();
12958 scope = newScope || scope;
12959 args = newArgs || args;
12961 id = setInterval(call, d);
12966 * Cancel the last queued timeout
12968 this.cancel = function(){
12976 * Ext JS Library 1.1.1
12977 * Copyright(c) 2006-2007, Ext JS, LLC.
12979 * Originally Released Under LGPL - original licence link has changed is not relivant.
12982 * <script type="text/javascript">
12986 Roo.util.TaskRunner = function(interval){
12987 interval = interval || 10;
12988 var tasks = [], removeQueue = [];
12990 var running = false;
12992 var stopThread = function(){
12998 var startThread = function(){
13001 id = setInterval(runTasks, interval);
13005 var removeTask = function(task){
13006 removeQueue.push(task);
13012 var runTasks = function(){
13013 if(removeQueue.length > 0){
13014 for(var i = 0, len = removeQueue.length; i < len; i++){
13015 tasks.remove(removeQueue[i]);
13018 if(tasks.length < 1){
13023 var now = new Date().getTime();
13024 for(var i = 0, len = tasks.length; i < len; ++i){
13026 var itime = now - t.taskRunTime;
13027 if(t.interval <= itime){
13028 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13029 t.taskRunTime = now;
13030 if(rt === false || t.taskRunCount === t.repeat){
13035 if(t.duration && t.duration <= (now - t.taskStartTime)){
13042 * Queues a new task.
13043 * @param {Object} task
13045 this.start = function(task){
13047 task.taskStartTime = new Date().getTime();
13048 task.taskRunTime = 0;
13049 task.taskRunCount = 0;
13054 this.stop = function(task){
13059 this.stopAll = function(){
13061 for(var i = 0, len = tasks.length; i < len; i++){
13062 if(tasks[i].onStop){
13071 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13073 * Ext JS Library 1.1.1
13074 * Copyright(c) 2006-2007, Ext JS, LLC.
13076 * Originally Released Under LGPL - original licence link has changed is not relivant.
13079 * <script type="text/javascript">
13084 * @class Roo.util.MixedCollection
13085 * @extends Roo.util.Observable
13086 * A Collection class that maintains both numeric indexes and keys and exposes events.
13088 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13089 * collection (defaults to false)
13090 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13091 * and return the key value for that item. This is used when available to look up the key on items that
13092 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13093 * equivalent to providing an implementation for the {@link #getKey} method.
13095 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13103 * Fires when the collection is cleared.
13108 * Fires when an item is added to the collection.
13109 * @param {Number} index The index at which the item was added.
13110 * @param {Object} o The item added.
13111 * @param {String} key The key associated with the added item.
13116 * Fires when an item is replaced in the collection.
13117 * @param {String} key he key associated with the new added.
13118 * @param {Object} old The item being replaced.
13119 * @param {Object} new The new item.
13124 * Fires when an item is removed from the collection.
13125 * @param {Object} o The item being removed.
13126 * @param {String} key (optional) The key associated with the removed item.
13131 this.allowFunctions = allowFunctions === true;
13133 this.getKey = keyFn;
13135 Roo.util.MixedCollection.superclass.constructor.call(this);
13138 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13139 allowFunctions : false,
13142 * Adds an item to the collection.
13143 * @param {String} key The key to associate with the item
13144 * @param {Object} o The item to add.
13145 * @return {Object} The item added.
13147 add : function(key, o){
13148 if(arguments.length == 1){
13150 key = this.getKey(o);
13152 if(typeof key == "undefined" || key === null){
13154 this.items.push(o);
13155 this.keys.push(null);
13157 var old = this.map[key];
13159 return this.replace(key, o);
13162 this.items.push(o);
13164 this.keys.push(key);
13166 this.fireEvent("add", this.length-1, o, key);
13171 * MixedCollection has a generic way to fetch keys if you implement getKey.
13174 var mc = new Roo.util.MixedCollection();
13175 mc.add(someEl.dom.id, someEl);
13176 mc.add(otherEl.dom.id, otherEl);
13180 var mc = new Roo.util.MixedCollection();
13181 mc.getKey = function(el){
13187 // or via the constructor
13188 var mc = new Roo.util.MixedCollection(false, function(el){
13194 * @param o {Object} The item for which to find the key.
13195 * @return {Object} The key for the passed item.
13197 getKey : function(o){
13202 * Replaces an item in the collection.
13203 * @param {String} key The key associated with the item to replace, or the item to replace.
13204 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13205 * @return {Object} The new item.
13207 replace : function(key, o){
13208 if(arguments.length == 1){
13210 key = this.getKey(o);
13212 var old = this.item(key);
13213 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13214 return this.add(key, o);
13216 var index = this.indexOfKey(key);
13217 this.items[index] = o;
13219 this.fireEvent("replace", key, old, o);
13224 * Adds all elements of an Array or an Object to the collection.
13225 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13226 * an Array of values, each of which are added to the collection.
13228 addAll : function(objs){
13229 if(arguments.length > 1 || objs instanceof Array){
13230 var args = arguments.length > 1 ? arguments : objs;
13231 for(var i = 0, len = args.length; i < len; i++){
13235 for(var key in objs){
13236 if(this.allowFunctions || typeof objs[key] != "function"){
13237 this.add(key, objs[key]);
13244 * Executes the specified function once for every item in the collection, passing each
13245 * item as the first and only parameter. returning false from the function will stop the iteration.
13246 * @param {Function} fn The function to execute for each item.
13247 * @param {Object} scope (optional) The scope in which to execute the function.
13249 each : function(fn, scope){
13250 var items = [].concat(this.items); // each safe for removal
13251 for(var i = 0, len = items.length; i < len; i++){
13252 if(fn.call(scope || items[i], items[i], i, len) === false){
13259 * Executes the specified function once for every key in the collection, passing each
13260 * key, and its associated item as the first two parameters.
13261 * @param {Function} fn The function to execute for each item.
13262 * @param {Object} scope (optional) The scope in which to execute the function.
13264 eachKey : function(fn, scope){
13265 for(var i = 0, len = this.keys.length; i < len; i++){
13266 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13271 * Returns the first item in the collection which elicits a true return value from the
13272 * passed selection function.
13273 * @param {Function} fn The selection function to execute for each item.
13274 * @param {Object} scope (optional) The scope in which to execute the function.
13275 * @return {Object} The first item in the collection which returned true from the selection function.
13277 find : function(fn, scope){
13278 for(var i = 0, len = this.items.length; i < len; i++){
13279 if(fn.call(scope || window, this.items[i], this.keys[i])){
13280 return this.items[i];
13287 * Inserts an item at the specified index in the collection.
13288 * @param {Number} index The index to insert the item at.
13289 * @param {String} key The key to associate with the new item, or the item itself.
13290 * @param {Object} o (optional) If the second parameter was a key, the new item.
13291 * @return {Object} The item inserted.
13293 insert : function(index, key, o){
13294 if(arguments.length == 2){
13296 key = this.getKey(o);
13298 if(index >= this.length){
13299 return this.add(key, o);
13302 this.items.splice(index, 0, o);
13303 if(typeof key != "undefined" && key != null){
13306 this.keys.splice(index, 0, key);
13307 this.fireEvent("add", index, o, key);
13312 * Removed an item from the collection.
13313 * @param {Object} o The item to remove.
13314 * @return {Object} The item removed.
13316 remove : function(o){
13317 return this.removeAt(this.indexOf(o));
13321 * Remove an item from a specified index in the collection.
13322 * @param {Number} index The index within the collection of the item to remove.
13324 removeAt : function(index){
13325 if(index < this.length && index >= 0){
13327 var o = this.items[index];
13328 this.items.splice(index, 1);
13329 var key = this.keys[index];
13330 if(typeof key != "undefined"){
13331 delete this.map[key];
13333 this.keys.splice(index, 1);
13334 this.fireEvent("remove", o, key);
13339 * Removed an item associated with the passed key fom the collection.
13340 * @param {String} key The key of the item to remove.
13342 removeKey : function(key){
13343 return this.removeAt(this.indexOfKey(key));
13347 * Returns the number of items in the collection.
13348 * @return {Number} the number of items in the collection.
13350 getCount : function(){
13351 return this.length;
13355 * Returns index within the collection of the passed Object.
13356 * @param {Object} o The item to find the index of.
13357 * @return {Number} index of the item.
13359 indexOf : function(o){
13360 if(!this.items.indexOf){
13361 for(var i = 0, len = this.items.length; i < len; i++){
13362 if(this.items[i] == o) {
13368 return this.items.indexOf(o);
13373 * Returns index within the collection of the passed key.
13374 * @param {String} key The key to find the index of.
13375 * @return {Number} index of the key.
13377 indexOfKey : function(key){
13378 if(!this.keys.indexOf){
13379 for(var i = 0, len = this.keys.length; i < len; i++){
13380 if(this.keys[i] == key) {
13386 return this.keys.indexOf(key);
13391 * Returns the item associated with the passed key OR index. Key has priority over index.
13392 * @param {String/Number} key The key or index of the item.
13393 * @return {Object} The item associated with the passed key.
13395 item : function(key){
13396 if (key === 'length') {
13399 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13400 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13404 * Returns the item at the specified index.
13405 * @param {Number} index The index of the item.
13408 itemAt : function(index){
13409 return this.items[index];
13413 * Returns the item associated with the passed key.
13414 * @param {String/Number} key The key of the item.
13415 * @return {Object} The item associated with the passed key.
13417 key : function(key){
13418 return this.map[key];
13422 * Returns true if the collection contains the passed Object as an item.
13423 * @param {Object} o The Object to look for in the collection.
13424 * @return {Boolean} True if the collection contains the Object as an item.
13426 contains : function(o){
13427 return this.indexOf(o) != -1;
13431 * Returns true if the collection contains the passed Object as a key.
13432 * @param {String} key The key to look for in the collection.
13433 * @return {Boolean} True if the collection contains the Object as a key.
13435 containsKey : function(key){
13436 return typeof this.map[key] != "undefined";
13440 * Removes all items from the collection.
13442 clear : function(){
13447 this.fireEvent("clear");
13451 * Returns the first item in the collection.
13452 * @return {Object} the first item in the collection..
13454 first : function(){
13455 return this.items[0];
13459 * Returns the last item in the collection.
13460 * @return {Object} the last item in the collection..
13463 return this.items[this.length-1];
13466 _sort : function(property, dir, fn){
13467 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13468 fn = fn || function(a, b){
13471 var c = [], k = this.keys, items = this.items;
13472 for(var i = 0, len = items.length; i < len; i++){
13473 c[c.length] = {key: k[i], value: items[i], index: i};
13475 c.sort(function(a, b){
13476 var v = fn(a[property], b[property]) * dsc;
13478 v = (a.index < b.index ? -1 : 1);
13482 for(var i = 0, len = c.length; i < len; i++){
13483 items[i] = c[i].value;
13486 this.fireEvent("sort", this);
13490 * Sorts this collection with the passed comparison function
13491 * @param {String} direction (optional) "ASC" or "DESC"
13492 * @param {Function} fn (optional) comparison function
13494 sort : function(dir, fn){
13495 this._sort("value", dir, fn);
13499 * Sorts this collection by keys
13500 * @param {String} direction (optional) "ASC" or "DESC"
13501 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13503 keySort : function(dir, fn){
13504 this._sort("key", dir, fn || function(a, b){
13505 return String(a).toUpperCase()-String(b).toUpperCase();
13510 * Returns a range of items in this collection
13511 * @param {Number} startIndex (optional) defaults to 0
13512 * @param {Number} endIndex (optional) default to the last item
13513 * @return {Array} An array of items
13515 getRange : function(start, end){
13516 var items = this.items;
13517 if(items.length < 1){
13520 start = start || 0;
13521 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13524 for(var i = start; i <= end; i++) {
13525 r[r.length] = items[i];
13528 for(var i = start; i >= end; i--) {
13529 r[r.length] = items[i];
13536 * Filter the <i>objects</i> in this collection by a specific property.
13537 * Returns a new collection that has been filtered.
13538 * @param {String} property A property on your objects
13539 * @param {String/RegExp} value Either string that the property values
13540 * should start with or a RegExp to test against the property
13541 * @return {MixedCollection} The new filtered collection
13543 filter : function(property, value){
13544 if(!value.exec){ // not a regex
13545 value = String(value);
13546 if(value.length == 0){
13547 return this.clone();
13549 value = new RegExp("^" + Roo.escapeRe(value), "i");
13551 return this.filterBy(function(o){
13552 return o && value.test(o[property]);
13557 * Filter by a function. * Returns a new collection that has been filtered.
13558 * The passed function will be called with each
13559 * object in the collection. If the function returns true, the value is included
13560 * otherwise it is filtered.
13561 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13562 * @param {Object} scope (optional) The scope of the function (defaults to this)
13563 * @return {MixedCollection} The new filtered collection
13565 filterBy : function(fn, scope){
13566 var r = new Roo.util.MixedCollection();
13567 r.getKey = this.getKey;
13568 var k = this.keys, it = this.items;
13569 for(var i = 0, len = it.length; i < len; i++){
13570 if(fn.call(scope||this, it[i], k[i])){
13571 r.add(k[i], it[i]);
13578 * Creates a duplicate of this collection
13579 * @return {MixedCollection}
13581 clone : function(){
13582 var r = new Roo.util.MixedCollection();
13583 var k = this.keys, it = this.items;
13584 for(var i = 0, len = it.length; i < len; i++){
13585 r.add(k[i], it[i]);
13587 r.getKey = this.getKey;
13592 * Returns the item associated with the passed key or index.
13594 * @param {String/Number} key The key or index of the item.
13595 * @return {Object} The item associated with the passed key.
13597 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13599 * Ext JS Library 1.1.1
13600 * Copyright(c) 2006-2007, Ext JS, LLC.
13602 * Originally Released Under LGPL - original licence link has changed is not relivant.
13605 * <script type="text/javascript">
13608 * @class Roo.util.JSON
13609 * Modified version of Douglas Crockford"s json.js that doesn"t
13610 * mess with the Object prototype
13611 * http://www.json.org/js.html
13614 Roo.util.JSON = new (function(){
13615 var useHasOwn = {}.hasOwnProperty ? true : false;
13617 // crashes Safari in some instances
13618 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13620 var pad = function(n) {
13621 return n < 10 ? "0" + n : n;
13634 var encodeString = function(s){
13635 if (/["\\\x00-\x1f]/.test(s)) {
13636 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13641 c = b.charCodeAt();
13643 Math.floor(c / 16).toString(16) +
13644 (c % 16).toString(16);
13647 return '"' + s + '"';
13650 var encodeArray = function(o){
13651 var a = ["["], b, i, l = o.length, v;
13652 for (i = 0; i < l; i += 1) {
13654 switch (typeof v) {
13663 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13671 var encodeDate = function(o){
13672 return '"' + o.getFullYear() + "-" +
13673 pad(o.getMonth() + 1) + "-" +
13674 pad(o.getDate()) + "T" +
13675 pad(o.getHours()) + ":" +
13676 pad(o.getMinutes()) + ":" +
13677 pad(o.getSeconds()) + '"';
13681 * Encodes an Object, Array or other value
13682 * @param {Mixed} o The variable to encode
13683 * @return {String} The JSON string
13685 this.encode = function(o)
13687 // should this be extended to fully wrap stringify..
13689 if(typeof o == "undefined" || o === null){
13691 }else if(o instanceof Array){
13692 return encodeArray(o);
13693 }else if(o instanceof Date){
13694 return encodeDate(o);
13695 }else if(typeof o == "string"){
13696 return encodeString(o);
13697 }else if(typeof o == "number"){
13698 return isFinite(o) ? String(o) : "null";
13699 }else if(typeof o == "boolean"){
13702 var a = ["{"], b, i, v;
13704 if(!useHasOwn || o.hasOwnProperty(i)) {
13706 switch (typeof v) {
13715 a.push(this.encode(i), ":",
13716 v === null ? "null" : this.encode(v));
13727 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13728 * @param {String} json The JSON string
13729 * @return {Object} The resulting object
13731 this.decode = function(json){
13733 return /** eval:var:json */ eval("(" + json + ')');
13737 * Shorthand for {@link Roo.util.JSON#encode}
13738 * @member Roo encode
13740 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13742 * Shorthand for {@link Roo.util.JSON#decode}
13743 * @member Roo decode
13745 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13748 * Ext JS Library 1.1.1
13749 * Copyright(c) 2006-2007, Ext JS, LLC.
13751 * Originally Released Under LGPL - original licence link has changed is not relivant.
13754 * <script type="text/javascript">
13758 * @class Roo.util.Format
13759 * Reusable data formatting functions
13762 Roo.util.Format = function(){
13763 var trimRe = /^\s+|\s+$/g;
13766 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13767 * @param {String} value The string to truncate
13768 * @param {Number} length The maximum length to allow before truncating
13769 * @return {String} The converted text
13771 ellipsis : function(value, len){
13772 if(value && value.length > len){
13773 return value.substr(0, len-3)+"...";
13779 * Checks a reference and converts it to empty string if it is undefined
13780 * @param {Mixed} value Reference to check
13781 * @return {Mixed} Empty string if converted, otherwise the original value
13783 undef : function(value){
13784 return typeof value != "undefined" ? value : "";
13788 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13789 * @param {String} value The string to encode
13790 * @return {String} The encoded text
13792 htmlEncode : function(value){
13793 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13797 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13798 * @param {String} value The string to decode
13799 * @return {String} The decoded text
13801 htmlDecode : function(value){
13802 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13806 * Trims any whitespace from either side of a string
13807 * @param {String} value The text to trim
13808 * @return {String} The trimmed text
13810 trim : function(value){
13811 return String(value).replace(trimRe, "");
13815 * Returns a substring from within an original string
13816 * @param {String} value The original text
13817 * @param {Number} start The start index of the substring
13818 * @param {Number} length The length of the substring
13819 * @return {String} The substring
13821 substr : function(value, start, length){
13822 return String(value).substr(start, length);
13826 * Converts a string to all lower case letters
13827 * @param {String} value The text to convert
13828 * @return {String} The converted text
13830 lowercase : function(value){
13831 return String(value).toLowerCase();
13835 * Converts a string to all upper case letters
13836 * @param {String} value The text to convert
13837 * @return {String} The converted text
13839 uppercase : function(value){
13840 return String(value).toUpperCase();
13844 * Converts the first character only of a string to upper case
13845 * @param {String} value The text to convert
13846 * @return {String} The converted text
13848 capitalize : function(value){
13849 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13853 call : function(value, fn){
13854 if(arguments.length > 2){
13855 var args = Array.prototype.slice.call(arguments, 2);
13856 args.unshift(value);
13858 return /** eval:var:value */ eval(fn).apply(window, args);
13860 /** eval:var:value */
13861 return /** eval:var:value */ eval(fn).call(window, value);
13867 * safer version of Math.toFixed..??/
13868 * @param {Number/String} value The numeric value to format
13869 * @param {Number/String} value Decimal places
13870 * @return {String} The formatted currency string
13872 toFixed : function(v, n)
13874 // why not use to fixed - precision is buggered???
13876 return Math.round(v-0);
13878 var fact = Math.pow(10,n+1);
13879 v = (Math.round((v-0)*fact))/fact;
13880 var z = (''+fact).substring(2);
13881 if (v == Math.floor(v)) {
13882 return Math.floor(v) + '.' + z;
13885 // now just padd decimals..
13886 var ps = String(v).split('.');
13887 var fd = (ps[1] + z);
13888 var r = fd.substring(0,n);
13889 var rm = fd.substring(n);
13891 return ps[0] + '.' + r;
13893 r*=1; // turn it into a number;
13895 if (String(r).length != n) {
13898 r = String(r).substring(1); // chop the end off.
13901 return ps[0] + '.' + r;
13906 * Format a number as US currency
13907 * @param {Number/String} value The numeric value to format
13908 * @return {String} The formatted currency string
13910 usMoney : function(v){
13911 return '$' + Roo.util.Format.number(v);
13916 * eventually this should probably emulate php's number_format
13917 * @param {Number/String} value The numeric value to format
13918 * @param {Number} decimals number of decimal places
13919 * @param {String} delimiter for thousands (default comma)
13920 * @return {String} The formatted currency string
13922 number : function(v, decimals, thousandsDelimiter)
13924 // multiply and round.
13925 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13926 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13928 var mul = Math.pow(10, decimals);
13929 var zero = String(mul).substring(1);
13930 v = (Math.round((v-0)*mul))/mul;
13932 // if it's '0' number.. then
13934 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13936 var ps = v.split('.');
13939 var r = /(\d+)(\d{3})/;
13942 if(thousandsDelimiter.length != 0) {
13943 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13948 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13949 // does not have decimals
13950 (decimals ? ('.' + zero) : '');
13953 return whole + sub ;
13957 * Parse a value into a formatted date using the specified format pattern.
13958 * @param {Mixed} value The value to format
13959 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13960 * @return {String} The formatted date string
13962 date : function(v, format){
13966 if(!(v instanceof Date)){
13967 v = new Date(Date.parse(v));
13969 return v.dateFormat(format || Roo.util.Format.defaults.date);
13973 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13974 * @param {String} format Any valid date format string
13975 * @return {Function} The date formatting function
13977 dateRenderer : function(format){
13978 return function(v){
13979 return Roo.util.Format.date(v, format);
13984 stripTagsRE : /<\/?[^>]+>/gi,
13987 * Strips all HTML tags
13988 * @param {Mixed} value The text from which to strip tags
13989 * @return {String} The stripped text
13991 stripTags : function(v){
13992 return !v ? v : String(v).replace(this.stripTagsRE, "");
13996 Roo.util.Format.defaults = {
14000 * Ext JS Library 1.1.1
14001 * Copyright(c) 2006-2007, Ext JS, LLC.
14003 * Originally Released Under LGPL - original licence link has changed is not relivant.
14006 * <script type="text/javascript">
14013 * @class Roo.MasterTemplate
14014 * @extends Roo.Template
14015 * Provides a template that can have child templates. The syntax is:
14017 var t = new Roo.MasterTemplate(
14018 '<select name="{name}">',
14019 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14022 t.add('options', {value: 'foo', text: 'bar'});
14023 // or you can add multiple child elements in one shot
14024 t.addAll('options', [
14025 {value: 'foo', text: 'bar'},
14026 {value: 'foo2', text: 'bar2'},
14027 {value: 'foo3', text: 'bar3'}
14029 // then append, applying the master template values
14030 t.append('my-form', {name: 'my-select'});
14032 * A name attribute for the child template is not required if you have only one child
14033 * template or you want to refer to them by index.
14035 Roo.MasterTemplate = function(){
14036 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14037 this.originalHtml = this.html;
14039 var m, re = this.subTemplateRe;
14042 while(m = re.exec(this.html)){
14043 var name = m[1], content = m[2];
14048 tpl : new Roo.Template(content)
14051 st[name] = st[subIndex];
14053 st[subIndex].tpl.compile();
14054 st[subIndex].tpl.call = this.call.createDelegate(this);
14057 this.subCount = subIndex;
14060 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14062 * The regular expression used to match sub templates
14066 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14069 * Applies the passed values to a child template.
14070 * @param {String/Number} name (optional) The name or index of the child template
14071 * @param {Array/Object} values The values to be applied to the template
14072 * @return {MasterTemplate} this
14074 add : function(name, values){
14075 if(arguments.length == 1){
14076 values = arguments[0];
14079 var s = this.subs[name];
14080 s.buffer[s.buffer.length] = s.tpl.apply(values);
14085 * Applies all the passed values to a child template.
14086 * @param {String/Number} name (optional) The name or index of the child template
14087 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14088 * @param {Boolean} reset (optional) True to reset the template first
14089 * @return {MasterTemplate} this
14091 fill : function(name, values, reset){
14093 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14101 for(var i = 0, len = values.length; i < len; i++){
14102 this.add(name, values[i]);
14108 * Resets the template for reuse
14109 * @return {MasterTemplate} this
14111 reset : function(){
14113 for(var i = 0; i < this.subCount; i++){
14119 applyTemplate : function(values){
14121 var replaceIndex = -1;
14122 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14123 return s[++replaceIndex].buffer.join("");
14125 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14128 apply : function(){
14129 return this.applyTemplate.apply(this, arguments);
14132 compile : function(){return this;}
14136 * Alias for fill().
14139 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14141 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14142 * var tpl = Roo.MasterTemplate.from('element-id');
14143 * @param {String/HTMLElement} el
14144 * @param {Object} config
14147 Roo.MasterTemplate.from = function(el, config){
14148 el = Roo.getDom(el);
14149 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14152 * Ext JS Library 1.1.1
14153 * Copyright(c) 2006-2007, Ext JS, LLC.
14155 * Originally Released Under LGPL - original licence link has changed is not relivant.
14158 * <script type="text/javascript">
14163 * @class Roo.util.CSS
14164 * Utility class for manipulating CSS rules
14167 Roo.util.CSS = function(){
14169 var doc = document;
14171 var camelRe = /(-[a-z])/gi;
14172 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14176 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14177 * tag and appended to the HEAD of the document.
14178 * @param {String|Object} cssText The text containing the css rules
14179 * @param {String} id An id to add to the stylesheet for later removal
14180 * @return {StyleSheet}
14182 createStyleSheet : function(cssText, id){
14184 var head = doc.getElementsByTagName("head")[0];
14185 var nrules = doc.createElement("style");
14186 nrules.setAttribute("type", "text/css");
14188 nrules.setAttribute("id", id);
14190 if (typeof(cssText) != 'string') {
14191 // support object maps..
14192 // not sure if this a good idea..
14193 // perhaps it should be merged with the general css handling
14194 // and handle js style props.
14195 var cssTextNew = [];
14196 for(var n in cssText) {
14198 for(var k in cssText[n]) {
14199 citems.push( k + ' : ' +cssText[n][k] + ';' );
14201 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14204 cssText = cssTextNew.join("\n");
14210 head.appendChild(nrules);
14211 ss = nrules.styleSheet;
14212 ss.cssText = cssText;
14215 nrules.appendChild(doc.createTextNode(cssText));
14217 nrules.cssText = cssText;
14219 head.appendChild(nrules);
14220 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14222 this.cacheStyleSheet(ss);
14227 * Removes a style or link tag by id
14228 * @param {String} id The id of the tag
14230 removeStyleSheet : function(id){
14231 var existing = doc.getElementById(id);
14233 existing.parentNode.removeChild(existing);
14238 * Dynamically swaps an existing stylesheet reference for a new one
14239 * @param {String} id The id of an existing link tag to remove
14240 * @param {String} url The href of the new stylesheet to include
14242 swapStyleSheet : function(id, url){
14243 this.removeStyleSheet(id);
14244 var ss = doc.createElement("link");
14245 ss.setAttribute("rel", "stylesheet");
14246 ss.setAttribute("type", "text/css");
14247 ss.setAttribute("id", id);
14248 ss.setAttribute("href", url);
14249 doc.getElementsByTagName("head")[0].appendChild(ss);
14253 * Refresh the rule cache if you have dynamically added stylesheets
14254 * @return {Object} An object (hash) of rules indexed by selector
14256 refreshCache : function(){
14257 return this.getRules(true);
14261 cacheStyleSheet : function(stylesheet){
14265 try{// try catch for cross domain access issue
14266 var ssRules = stylesheet.cssRules || stylesheet.rules;
14267 for(var j = ssRules.length-1; j >= 0; --j){
14268 rules[ssRules[j].selectorText] = ssRules[j];
14274 * Gets all css rules for the document
14275 * @param {Boolean} refreshCache true to refresh the internal cache
14276 * @return {Object} An object (hash) of rules indexed by selector
14278 getRules : function(refreshCache){
14279 if(rules == null || refreshCache){
14281 var ds = doc.styleSheets;
14282 for(var i =0, len = ds.length; i < len; i++){
14284 this.cacheStyleSheet(ds[i]);
14292 * Gets an an individual CSS rule by selector(s)
14293 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14294 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14295 * @return {CSSRule} The CSS rule or null if one is not found
14297 getRule : function(selector, refreshCache){
14298 var rs = this.getRules(refreshCache);
14299 if(!(selector instanceof Array)){
14300 return rs[selector];
14302 for(var i = 0; i < selector.length; i++){
14303 if(rs[selector[i]]){
14304 return rs[selector[i]];
14312 * Updates a rule property
14313 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14314 * @param {String} property The css property
14315 * @param {String} value The new value for the property
14316 * @return {Boolean} true If a rule was found and updated
14318 updateRule : function(selector, property, value){
14319 if(!(selector instanceof Array)){
14320 var rule = this.getRule(selector);
14322 rule.style[property.replace(camelRe, camelFn)] = value;
14326 for(var i = 0; i < selector.length; i++){
14327 if(this.updateRule(selector[i], property, value)){
14337 * Ext JS Library 1.1.1
14338 * Copyright(c) 2006-2007, Ext JS, LLC.
14340 * Originally Released Under LGPL - original licence link has changed is not relivant.
14343 * <script type="text/javascript">
14349 * @class Roo.util.ClickRepeater
14350 * @extends Roo.util.Observable
14352 * A wrapper class which can be applied to any element. Fires a "click" event while the
14353 * mouse is pressed. The interval between firings may be specified in the config but
14354 * defaults to 10 milliseconds.
14356 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14358 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14359 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14360 * Similar to an autorepeat key delay.
14361 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14362 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14363 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14364 * "interval" and "delay" are ignored. "immediate" is honored.
14365 * @cfg {Boolean} preventDefault True to prevent the default click event
14366 * @cfg {Boolean} stopDefault True to stop the default click event
14369 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14370 * 2007-02-02 jvs Renamed to ClickRepeater
14371 * 2007-02-03 jvs Modifications for FF Mac and Safari
14374 * @param {String/HTMLElement/Element} el The element to listen on
14375 * @param {Object} config
14377 Roo.util.ClickRepeater = function(el, config)
14379 this.el = Roo.get(el);
14380 this.el.unselectable();
14382 Roo.apply(this, config);
14387 * Fires when the mouse button is depressed.
14388 * @param {Roo.util.ClickRepeater} this
14390 "mousedown" : true,
14393 * Fires on a specified interval during the time the element is pressed.
14394 * @param {Roo.util.ClickRepeater} this
14399 * Fires when the mouse key is released.
14400 * @param {Roo.util.ClickRepeater} this
14405 this.el.on("mousedown", this.handleMouseDown, this);
14406 if(this.preventDefault || this.stopDefault){
14407 this.el.on("click", function(e){
14408 if(this.preventDefault){
14409 e.preventDefault();
14411 if(this.stopDefault){
14417 // allow inline handler
14419 this.on("click", this.handler, this.scope || this);
14422 Roo.util.ClickRepeater.superclass.constructor.call(this);
14425 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14428 preventDefault : true,
14429 stopDefault : false,
14433 handleMouseDown : function(){
14434 clearTimeout(this.timer);
14436 if(this.pressClass){
14437 this.el.addClass(this.pressClass);
14439 this.mousedownTime = new Date();
14441 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14442 this.el.on("mouseout", this.handleMouseOut, this);
14444 this.fireEvent("mousedown", this);
14445 this.fireEvent("click", this);
14447 this.timer = this.click.defer(this.delay || this.interval, this);
14451 click : function(){
14452 this.fireEvent("click", this);
14453 this.timer = this.click.defer(this.getInterval(), this);
14457 getInterval: function(){
14458 if(!this.accelerate){
14459 return this.interval;
14461 var pressTime = this.mousedownTime.getElapsed();
14462 if(pressTime < 500){
14464 }else if(pressTime < 1700){
14466 }else if(pressTime < 2600){
14468 }else if(pressTime < 3500){
14470 }else if(pressTime < 4400){
14472 }else if(pressTime < 5300){
14474 }else if(pressTime < 6200){
14482 handleMouseOut : function(){
14483 clearTimeout(this.timer);
14484 if(this.pressClass){
14485 this.el.removeClass(this.pressClass);
14487 this.el.on("mouseover", this.handleMouseReturn, this);
14491 handleMouseReturn : function(){
14492 this.el.un("mouseover", this.handleMouseReturn);
14493 if(this.pressClass){
14494 this.el.addClass(this.pressClass);
14500 handleMouseUp : function(){
14501 clearTimeout(this.timer);
14502 this.el.un("mouseover", this.handleMouseReturn);
14503 this.el.un("mouseout", this.handleMouseOut);
14504 Roo.get(document).un("mouseup", this.handleMouseUp);
14505 this.el.removeClass(this.pressClass);
14506 this.fireEvent("mouseup", this);
14509 * @class Roo.util.Clipboard
14515 Roo.util.Clipboard = {
14517 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
14518 * @param {String} text to copy to clipboard
14520 write : function(text) {
14521 // navigator clipboard api needs a secure context (https)
14522 if (navigator.clipboard && window.isSecureContext) {
14523 // navigator clipboard api method'
14524 navigator.clipboard.writeText(text);
14527 // text area method
14528 var ta = document.createElement("textarea");
14530 // make the textarea out of viewport
14531 ta.style.position = "fixed";
14532 ta.style.left = "-999999px";
14533 ta.style.top = "-999999px";
14534 document.body.appendChild(ta);
14537 document.execCommand('copy');
14547 * Ext JS Library 1.1.1
14548 * Copyright(c) 2006-2007, Ext JS, LLC.
14550 * Originally Released Under LGPL - original licence link has changed is not relivant.
14553 * <script type="text/javascript">
14558 * @class Roo.KeyNav
14559 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14560 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14561 * way to implement custom navigation schemes for any UI component.</p>
14562 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14563 * pageUp, pageDown, del, home, end. Usage:</p>
14565 var nav = new Roo.KeyNav("my-element", {
14566 "left" : function(e){
14567 this.moveLeft(e.ctrlKey);
14569 "right" : function(e){
14570 this.moveRight(e.ctrlKey);
14572 "enter" : function(e){
14579 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14580 * @param {Object} config The config
14582 Roo.KeyNav = function(el, config){
14583 this.el = Roo.get(el);
14584 Roo.apply(this, config);
14585 if(!this.disabled){
14586 this.disabled = true;
14591 Roo.KeyNav.prototype = {
14593 * @cfg {Boolean} disabled
14594 * True to disable this KeyNav instance (defaults to false)
14598 * @cfg {String} defaultEventAction
14599 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14600 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14601 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14603 defaultEventAction: "stopEvent",
14605 * @cfg {Boolean} forceKeyDown
14606 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14607 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14608 * handle keydown instead of keypress.
14610 forceKeyDown : false,
14613 prepareEvent : function(e){
14614 var k = e.getKey();
14615 var h = this.keyToHandler[k];
14616 //if(h && this[h]){
14617 // e.stopPropagation();
14619 if(Roo.isSafari && h && k >= 37 && k <= 40){
14625 relay : function(e){
14626 var k = e.getKey();
14627 var h = this.keyToHandler[k];
14629 if(this.doRelay(e, this[h], h) !== true){
14630 e[this.defaultEventAction]();
14636 doRelay : function(e, h, hname){
14637 return h.call(this.scope || this, e);
14640 // possible handlers
14654 // quick lookup hash
14671 * Enable this KeyNav
14673 enable: function(){
14675 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14676 // the EventObject will normalize Safari automatically
14677 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14678 this.el.on("keydown", this.relay, this);
14680 this.el.on("keydown", this.prepareEvent, this);
14681 this.el.on("keypress", this.relay, this);
14683 this.disabled = false;
14688 * Disable this KeyNav
14690 disable: function(){
14691 if(!this.disabled){
14692 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14693 this.el.un("keydown", this.relay);
14695 this.el.un("keydown", this.prepareEvent);
14696 this.el.un("keypress", this.relay);
14698 this.disabled = true;
14703 * Ext JS Library 1.1.1
14704 * Copyright(c) 2006-2007, Ext JS, LLC.
14706 * Originally Released Under LGPL - original licence link has changed is not relivant.
14709 * <script type="text/javascript">
14714 * @class Roo.KeyMap
14715 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14716 * The constructor accepts the same config object as defined by {@link #addBinding}.
14717 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14718 * combination it will call the function with this signature (if the match is a multi-key
14719 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14720 * A KeyMap can also handle a string representation of keys.<br />
14723 // map one key by key code
14724 var map = new Roo.KeyMap("my-element", {
14725 key: 13, // or Roo.EventObject.ENTER
14730 // map multiple keys to one action by string
14731 var map = new Roo.KeyMap("my-element", {
14737 // map multiple keys to multiple actions by strings and array of codes
14738 var map = new Roo.KeyMap("my-element", [
14741 fn: function(){ alert("Return was pressed"); }
14744 fn: function(){ alert('a, b or c was pressed'); }
14749 fn: function(){ alert('Control + shift + tab was pressed.'); }
14753 * <b>Note: A KeyMap starts enabled</b>
14755 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14756 * @param {Object} config The config (see {@link #addBinding})
14757 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14759 Roo.KeyMap = function(el, config, eventName){
14760 this.el = Roo.get(el);
14761 this.eventName = eventName || "keydown";
14762 this.bindings = [];
14764 this.addBinding(config);
14769 Roo.KeyMap.prototype = {
14771 * True to stop the event from bubbling and prevent the default browser action if the
14772 * key was handled by the KeyMap (defaults to false)
14778 * Add a new binding to this KeyMap. The following config object properties are supported:
14780 Property Type Description
14781 ---------- --------------- ----------------------------------------------------------------------
14782 key String/Array A single keycode or an array of keycodes to handle
14783 shift Boolean True to handle key only when shift is pressed (defaults to false)
14784 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14785 alt Boolean True to handle key only when alt is pressed (defaults to false)
14786 fn Function The function to call when KeyMap finds the expected key combination
14787 scope Object The scope of the callback function
14793 var map = new Roo.KeyMap(document, {
14794 key: Roo.EventObject.ENTER,
14799 //Add a new binding to the existing KeyMap later
14807 * @param {Object/Array} config A single KeyMap config or an array of configs
14809 addBinding : function(config){
14810 if(config instanceof Array){
14811 for(var i = 0, len = config.length; i < len; i++){
14812 this.addBinding(config[i]);
14816 var keyCode = config.key,
14817 shift = config.shift,
14818 ctrl = config.ctrl,
14821 scope = config.scope;
14822 if(typeof keyCode == "string"){
14824 var keyString = keyCode.toUpperCase();
14825 for(var j = 0, len = keyString.length; j < len; j++){
14826 ks.push(keyString.charCodeAt(j));
14830 var keyArray = keyCode instanceof Array;
14831 var handler = function(e){
14832 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14833 var k = e.getKey();
14835 for(var i = 0, len = keyCode.length; i < len; i++){
14836 if(keyCode[i] == k){
14837 if(this.stopEvent){
14840 fn.call(scope || window, k, e);
14846 if(this.stopEvent){
14849 fn.call(scope || window, k, e);
14854 this.bindings.push(handler);
14858 * Shorthand for adding a single key listener
14859 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14860 * following options:
14861 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14862 * @param {Function} fn The function to call
14863 * @param {Object} scope (optional) The scope of the function
14865 on : function(key, fn, scope){
14866 var keyCode, shift, ctrl, alt;
14867 if(typeof key == "object" && !(key instanceof Array)){
14886 handleKeyDown : function(e){
14887 if(this.enabled){ //just in case
14888 var b = this.bindings;
14889 for(var i = 0, len = b.length; i < len; i++){
14890 b[i].call(this, e);
14896 * Returns true if this KeyMap is enabled
14897 * @return {Boolean}
14899 isEnabled : function(){
14900 return this.enabled;
14904 * Enables this KeyMap
14906 enable: function(){
14908 this.el.on(this.eventName, this.handleKeyDown, this);
14909 this.enabled = true;
14914 * Disable this KeyMap
14916 disable: function(){
14918 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14919 this.enabled = false;
14924 * Ext JS Library 1.1.1
14925 * Copyright(c) 2006-2007, Ext JS, LLC.
14927 * Originally Released Under LGPL - original licence link has changed is not relivant.
14930 * <script type="text/javascript">
14935 * @class Roo.util.TextMetrics
14936 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14937 * wide, in pixels, a given block of text will be.
14940 Roo.util.TextMetrics = function(){
14944 * Measures the size of the specified text
14945 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14946 * that can affect the size of the rendered text
14947 * @param {String} text The text to measure
14948 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14949 * in order to accurately measure the text height
14950 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14952 measure : function(el, text, fixedWidth){
14954 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14957 shared.setFixedWidth(fixedWidth || 'auto');
14958 return shared.getSize(text);
14962 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14963 * the overhead of multiple calls to initialize the style properties on each measurement.
14964 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14965 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14966 * in order to accurately measure the text height
14967 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14969 createInstance : function(el, fixedWidth){
14970 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14977 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14978 var ml = new Roo.Element(document.createElement('div'));
14979 document.body.appendChild(ml.dom);
14980 ml.position('absolute');
14981 ml.setLeftTop(-1000, -1000);
14985 ml.setWidth(fixedWidth);
14990 * Returns the size of the specified text based on the internal element's style and width properties
14991 * @memberOf Roo.util.TextMetrics.Instance#
14992 * @param {String} text The text to measure
14993 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14995 getSize : function(text){
14997 var s = ml.getSize();
15003 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15004 * that can affect the size of the rendered text
15005 * @memberOf Roo.util.TextMetrics.Instance#
15006 * @param {String/HTMLElement} el The element, dom node or id
15008 bind : function(el){
15010 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15015 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15016 * to set a fixed width in order to accurately measure the text height.
15017 * @memberOf Roo.util.TextMetrics.Instance#
15018 * @param {Number} width The width to set on the element
15020 setFixedWidth : function(width){
15021 ml.setWidth(width);
15025 * Returns the measured width of the specified text
15026 * @memberOf Roo.util.TextMetrics.Instance#
15027 * @param {String} text The text to measure
15028 * @return {Number} width The width in pixels
15030 getWidth : function(text){
15031 ml.dom.style.width = 'auto';
15032 return this.getSize(text).width;
15036 * Returns the measured height of the specified text. For multiline text, be sure to call
15037 * {@link #setFixedWidth} if necessary.
15038 * @memberOf Roo.util.TextMetrics.Instance#
15039 * @param {String} text The text to measure
15040 * @return {Number} height The height in pixels
15042 getHeight : function(text){
15043 return this.getSize(text).height;
15047 instance.bind(bindTo);
15052 // backwards compat
15053 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15055 * Ext JS Library 1.1.1
15056 * Copyright(c) 2006-2007, Ext JS, LLC.
15058 * Originally Released Under LGPL - original licence link has changed is not relivant.
15061 * <script type="text/javascript">
15065 * @class Roo.state.Provider
15066 * Abstract base class for state provider implementations. This class provides methods
15067 * for encoding and decoding <b>typed</b> variables including dates and defines the
15068 * Provider interface.
15070 Roo.state.Provider = function(){
15072 * @event statechange
15073 * Fires when a state change occurs.
15074 * @param {Provider} this This state provider
15075 * @param {String} key The state key which was changed
15076 * @param {String} value The encoded value for the state
15079 "statechange": true
15082 Roo.state.Provider.superclass.constructor.call(this);
15084 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15086 * Returns the current value for a key
15087 * @param {String} name The key name
15088 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15089 * @return {Mixed} The state data
15091 get : function(name, defaultValue){
15092 return typeof this.state[name] == "undefined" ?
15093 defaultValue : this.state[name];
15097 * Clears a value from the state
15098 * @param {String} name The key name
15100 clear : function(name){
15101 delete this.state[name];
15102 this.fireEvent("statechange", this, name, null);
15106 * Sets the value for a key
15107 * @param {String} name The key name
15108 * @param {Mixed} value The value to set
15110 set : function(name, value){
15111 this.state[name] = value;
15112 this.fireEvent("statechange", this, name, value);
15116 * Decodes a string previously encoded with {@link #encodeValue}.
15117 * @param {String} value The value to decode
15118 * @return {Mixed} The decoded value
15120 decodeValue : function(cookie){
15121 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15122 var matches = re.exec(unescape(cookie));
15123 if(!matches || !matches[1]) {
15124 return; // non state cookie
15126 var type = matches[1];
15127 var v = matches[2];
15130 return parseFloat(v);
15132 return new Date(Date.parse(v));
15137 var values = v.split("^");
15138 for(var i = 0, len = values.length; i < len; i++){
15139 all.push(this.decodeValue(values[i]));
15144 var values = v.split("^");
15145 for(var i = 0, len = values.length; i < len; i++){
15146 var kv = values[i].split("=");
15147 all[kv[0]] = this.decodeValue(kv[1]);
15156 * Encodes a value including type information. Decode with {@link #decodeValue}.
15157 * @param {Mixed} value The value to encode
15158 * @return {String} The encoded value
15160 encodeValue : function(v){
15162 if(typeof v == "number"){
15164 }else if(typeof v == "boolean"){
15165 enc = "b:" + (v ? "1" : "0");
15166 }else if(v instanceof Date){
15167 enc = "d:" + v.toGMTString();
15168 }else if(v instanceof Array){
15170 for(var i = 0, len = v.length; i < len; i++){
15171 flat += this.encodeValue(v[i]);
15177 }else if(typeof v == "object"){
15180 if(typeof v[key] != "function"){
15181 flat += key + "=" + this.encodeValue(v[key]) + "^";
15184 enc = "o:" + flat.substring(0, flat.length-1);
15188 return escape(enc);
15194 * Ext JS Library 1.1.1
15195 * Copyright(c) 2006-2007, Ext JS, LLC.
15197 * Originally Released Under LGPL - original licence link has changed is not relivant.
15200 * <script type="text/javascript">
15203 * @class Roo.state.Manager
15204 * This is the global state manager. By default all components that are "state aware" check this class
15205 * for state information if you don't pass them a custom state provider. In order for this class
15206 * to be useful, it must be initialized with a provider when your application initializes.
15208 // in your initialization function
15210 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15212 // supposed you have a {@link Roo.BorderLayout}
15213 var layout = new Roo.BorderLayout(...);
15214 layout.restoreState();
15215 // or a {Roo.BasicDialog}
15216 var dialog = new Roo.BasicDialog(...);
15217 dialog.restoreState();
15221 Roo.state.Manager = function(){
15222 var provider = new Roo.state.Provider();
15226 * Configures the default state provider for your application
15227 * @param {Provider} stateProvider The state provider to set
15229 setProvider : function(stateProvider){
15230 provider = stateProvider;
15234 * Returns the current value for a key
15235 * @param {String} name The key name
15236 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15237 * @return {Mixed} The state data
15239 get : function(key, defaultValue){
15240 return provider.get(key, defaultValue);
15244 * Sets the value for a key
15245 * @param {String} name The key name
15246 * @param {Mixed} value The state data
15248 set : function(key, value){
15249 provider.set(key, value);
15253 * Clears a value from the state
15254 * @param {String} name The key name
15256 clear : function(key){
15257 provider.clear(key);
15261 * Gets the currently configured state provider
15262 * @return {Provider} The state provider
15264 getProvider : function(){
15271 * Ext JS Library 1.1.1
15272 * Copyright(c) 2006-2007, Ext JS, LLC.
15274 * Originally Released Under LGPL - original licence link has changed is not relivant.
15277 * <script type="text/javascript">
15280 * @class Roo.state.CookieProvider
15281 * @extends Roo.state.Provider
15282 * The default Provider implementation which saves state via cookies.
15285 var cp = new Roo.state.CookieProvider({
15287 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15288 domain: "roojs.com"
15290 Roo.state.Manager.setProvider(cp);
15292 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15293 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15294 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15295 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15296 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15297 * domain the page is running on including the 'www' like 'www.roojs.com')
15298 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15300 * Create a new CookieProvider
15301 * @param {Object} config The configuration object
15303 Roo.state.CookieProvider = function(config){
15304 Roo.state.CookieProvider.superclass.constructor.call(this);
15306 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15307 this.domain = null;
15308 this.secure = false;
15309 Roo.apply(this, config);
15310 this.state = this.readCookies();
15313 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15315 set : function(name, value){
15316 if(typeof value == "undefined" || value === null){
15320 this.setCookie(name, value);
15321 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15325 clear : function(name){
15326 this.clearCookie(name);
15327 Roo.state.CookieProvider.superclass.clear.call(this, name);
15331 readCookies : function(){
15333 var c = document.cookie + ";";
15334 var re = /\s?(.*?)=(.*?);/g;
15336 while((matches = re.exec(c)) != null){
15337 var name = matches[1];
15338 var value = matches[2];
15339 if(name && name.substring(0,3) == "ys-"){
15340 cookies[name.substr(3)] = this.decodeValue(value);
15347 setCookie : function(name, value){
15348 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15349 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15350 ((this.path == null) ? "" : ("; path=" + this.path)) +
15351 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15352 ((this.secure == true) ? "; secure" : "");
15356 clearCookie : function(name){
15357 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15358 ((this.path == null) ? "" : ("; path=" + this.path)) +
15359 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15360 ((this.secure == true) ? "; secure" : "");
15364 * Ext JS Library 1.1.1
15365 * Copyright(c) 2006-2007, Ext JS, LLC.
15367 * Originally Released Under LGPL - original licence link has changed is not relivant.
15370 * <script type="text/javascript">
15375 * @class Roo.ComponentMgr
15376 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15379 Roo.ComponentMgr = function(){
15380 var all = new Roo.util.MixedCollection();
15384 * Registers a component.
15385 * @param {Roo.Component} c The component
15387 register : function(c){
15392 * Unregisters a component.
15393 * @param {Roo.Component} c The component
15395 unregister : function(c){
15400 * Returns a component by id
15401 * @param {String} id The component id
15403 get : function(id){
15404 return all.get(id);
15408 * Registers a function that will be called when a specified component is added to ComponentMgr
15409 * @param {String} id The component id
15410 * @param {Funtction} fn The callback function
15411 * @param {Object} scope The scope of the callback
15413 onAvailable : function(id, fn, scope){
15414 all.on("add", function(index, o){
15416 fn.call(scope || o, o);
15417 all.un("add", fn, scope);
15424 * Ext JS Library 1.1.1
15425 * Copyright(c) 2006-2007, Ext JS, LLC.
15427 * Originally Released Under LGPL - original licence link has changed is not relivant.
15430 * <script type="text/javascript">
15434 * @class Roo.Component
15435 * @extends Roo.util.Observable
15436 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15437 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15438 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15439 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15440 * All visual components (widgets) that require rendering into a layout should subclass Component.
15442 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15443 * 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
15444 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15446 Roo.Component = function(config){
15447 config = config || {};
15448 if(config.tagName || config.dom || typeof config == "string"){ // element object
15449 config = {el: config, id: config.id || config};
15451 this.initialConfig = config;
15453 Roo.apply(this, config);
15457 * Fires after the component is disabled.
15458 * @param {Roo.Component} this
15463 * Fires after the component is enabled.
15464 * @param {Roo.Component} this
15468 * @event beforeshow
15469 * Fires before the component is shown. Return false to stop the show.
15470 * @param {Roo.Component} this
15475 * Fires after the component is shown.
15476 * @param {Roo.Component} this
15480 * @event beforehide
15481 * Fires before the component is hidden. Return false to stop the hide.
15482 * @param {Roo.Component} this
15487 * Fires after the component is hidden.
15488 * @param {Roo.Component} this
15492 * @event beforerender
15493 * Fires before the component is rendered. Return false to stop the render.
15494 * @param {Roo.Component} this
15496 beforerender : true,
15499 * Fires after the component is rendered.
15500 * @param {Roo.Component} this
15504 * @event beforedestroy
15505 * Fires before the component is destroyed. Return false to stop the destroy.
15506 * @param {Roo.Component} this
15508 beforedestroy : true,
15511 * Fires after the component is destroyed.
15512 * @param {Roo.Component} this
15517 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15519 Roo.ComponentMgr.register(this);
15520 Roo.Component.superclass.constructor.call(this);
15521 this.initComponent();
15522 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15523 this.render(this.renderTo);
15524 delete this.renderTo;
15529 Roo.Component.AUTO_ID = 1000;
15531 Roo.extend(Roo.Component, Roo.util.Observable, {
15533 * @scope Roo.Component.prototype
15535 * true if this component is hidden. Read-only.
15540 * true if this component is disabled. Read-only.
15545 * true if this component has been rendered. Read-only.
15549 /** @cfg {String} disableClass
15550 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15552 disabledClass : "x-item-disabled",
15553 /** @cfg {Boolean} allowDomMove
15554 * Whether the component can move the Dom node when rendering (defaults to true).
15556 allowDomMove : true,
15557 /** @cfg {String} hideMode (display|visibility)
15558 * How this component should hidden. Supported values are
15559 * "visibility" (css visibility), "offsets" (negative offset position) and
15560 * "display" (css display) - defaults to "display".
15562 hideMode: 'display',
15565 ctype : "Roo.Component",
15568 * @cfg {String} actionMode
15569 * which property holds the element that used for hide() / show() / disable() / enable()
15570 * default is 'el' for forms you probably want to set this to fieldEl
15575 getActionEl : function(){
15576 return this[this.actionMode];
15579 initComponent : Roo.emptyFn,
15581 * If this is a lazy rendering component, render it to its container element.
15582 * @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.
15584 render : function(container, position){
15590 if(this.fireEvent("beforerender", this) === false){
15594 if(!container && this.el){
15595 this.el = Roo.get(this.el);
15596 container = this.el.dom.parentNode;
15597 this.allowDomMove = false;
15599 this.container = Roo.get(container);
15600 this.rendered = true;
15601 if(position !== undefined){
15602 if(typeof position == 'number'){
15603 position = this.container.dom.childNodes[position];
15605 position = Roo.getDom(position);
15608 this.onRender(this.container, position || null);
15610 this.el.addClass(this.cls);
15614 this.el.applyStyles(this.style);
15617 this.fireEvent("render", this);
15618 this.afterRender(this.container);
15631 // default function is not really useful
15632 onRender : function(ct, position){
15634 this.el = Roo.get(this.el);
15635 if(this.allowDomMove !== false){
15636 ct.dom.insertBefore(this.el.dom, position);
15642 getAutoCreate : function(){
15643 var cfg = typeof this.autoCreate == "object" ?
15644 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15645 if(this.id && !cfg.id){
15652 afterRender : Roo.emptyFn,
15655 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15656 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15658 destroy : function(){
15659 if(this.fireEvent("beforedestroy", this) !== false){
15660 this.purgeListeners();
15661 this.beforeDestroy();
15663 this.el.removeAllListeners();
15665 if(this.actionMode == "container"){
15666 this.container.remove();
15670 Roo.ComponentMgr.unregister(this);
15671 this.fireEvent("destroy", this);
15676 beforeDestroy : function(){
15681 onDestroy : function(){
15686 * Returns the underlying {@link Roo.Element}.
15687 * @return {Roo.Element} The element
15689 getEl : function(){
15694 * Returns the id of this component.
15697 getId : function(){
15702 * Try to focus this component.
15703 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15704 * @return {Roo.Component} this
15706 focus : function(selectText){
15709 if(selectText === true){
15710 this.el.dom.select();
15725 * Disable this component.
15726 * @return {Roo.Component} this
15728 disable : function(){
15732 this.disabled = true;
15733 this.fireEvent("disable", this);
15738 onDisable : function(){
15739 this.getActionEl().addClass(this.disabledClass);
15740 this.el.dom.disabled = true;
15744 * Enable this component.
15745 * @return {Roo.Component} this
15747 enable : function(){
15751 this.disabled = false;
15752 this.fireEvent("enable", this);
15757 onEnable : function(){
15758 this.getActionEl().removeClass(this.disabledClass);
15759 this.el.dom.disabled = false;
15763 * Convenience function for setting disabled/enabled by boolean.
15764 * @param {Boolean} disabled
15766 setDisabled : function(disabled){
15767 this[disabled ? "disable" : "enable"]();
15771 * Show this component.
15772 * @return {Roo.Component} this
15775 if(this.fireEvent("beforeshow", this) !== false){
15776 this.hidden = false;
15780 this.fireEvent("show", this);
15786 onShow : function(){
15787 var ae = this.getActionEl();
15788 if(this.hideMode == 'visibility'){
15789 ae.dom.style.visibility = "visible";
15790 }else if(this.hideMode == 'offsets'){
15791 ae.removeClass('x-hidden');
15793 ae.dom.style.display = "";
15798 * Hide this component.
15799 * @return {Roo.Component} this
15802 if(this.fireEvent("beforehide", this) !== false){
15803 this.hidden = true;
15807 this.fireEvent("hide", this);
15813 onHide : function(){
15814 var ae = this.getActionEl();
15815 if(this.hideMode == 'visibility'){
15816 ae.dom.style.visibility = "hidden";
15817 }else if(this.hideMode == 'offsets'){
15818 ae.addClass('x-hidden');
15820 ae.dom.style.display = "none";
15825 * Convenience function to hide or show this component by boolean.
15826 * @param {Boolean} visible True to show, false to hide
15827 * @return {Roo.Component} this
15829 setVisible: function(visible){
15839 * Returns true if this component is visible.
15841 isVisible : function(){
15842 return this.getActionEl().isVisible();
15845 cloneConfig : function(overrides){
15846 overrides = overrides || {};
15847 var id = overrides.id || Roo.id();
15848 var cfg = Roo.applyIf(overrides, this.initialConfig);
15849 cfg.id = id; // prevent dup id
15850 return new this.constructor(cfg);
15854 * Ext JS Library 1.1.1
15855 * Copyright(c) 2006-2007, Ext JS, LLC.
15857 * Originally Released Under LGPL - original licence link has changed is not relivant.
15860 * <script type="text/javascript">
15864 * @class Roo.BoxComponent
15865 * @extends Roo.Component
15866 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15867 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15868 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15869 * layout containers.
15871 * @param {Roo.Element/String/Object} config The configuration options.
15873 Roo.BoxComponent = function(config){
15874 Roo.Component.call(this, config);
15878 * Fires after the component is resized.
15879 * @param {Roo.Component} this
15880 * @param {Number} adjWidth The box-adjusted width that was set
15881 * @param {Number} adjHeight The box-adjusted height that was set
15882 * @param {Number} rawWidth The width that was originally specified
15883 * @param {Number} rawHeight The height that was originally specified
15888 * Fires after the component is moved.
15889 * @param {Roo.Component} this
15890 * @param {Number} x The new x position
15891 * @param {Number} y The new y position
15897 Roo.extend(Roo.BoxComponent, Roo.Component, {
15898 // private, set in afterRender to signify that the component has been rendered
15900 // private, used to defer height settings to subclasses
15901 deferHeight: false,
15902 /** @cfg {Number} width
15903 * width (optional) size of component
15905 /** @cfg {Number} height
15906 * height (optional) size of component
15910 * Sets the width and height of the component. This method fires the resize event. This method can accept
15911 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15912 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15913 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15914 * @return {Roo.BoxComponent} this
15916 setSize : function(w, h){
15917 // support for standard size objects
15918 if(typeof w == 'object'){
15923 if(!this.boxReady){
15929 // prevent recalcs when not needed
15930 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15933 this.lastSize = {width: w, height: h};
15935 var adj = this.adjustSize(w, h);
15936 var aw = adj.width, ah = adj.height;
15937 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15938 var rz = this.getResizeEl();
15939 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15940 rz.setSize(aw, ah);
15941 }else if(!this.deferHeight && ah !== undefined){
15943 }else if(aw !== undefined){
15946 this.onResize(aw, ah, w, h);
15947 this.fireEvent('resize', this, aw, ah, w, h);
15953 * Gets the current size of the component's underlying element.
15954 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15956 getSize : function(){
15957 return this.el.getSize();
15961 * Gets the current XY position of the component's underlying element.
15962 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15963 * @return {Array} The XY position of the element (e.g., [100, 200])
15965 getPosition : function(local){
15966 if(local === true){
15967 return [this.el.getLeft(true), this.el.getTop(true)];
15969 return this.xy || this.el.getXY();
15973 * Gets the current box measurements of the component's underlying element.
15974 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15975 * @returns {Object} box An object in the format {x, y, width, height}
15977 getBox : function(local){
15978 var s = this.el.getSize();
15980 s.x = this.el.getLeft(true);
15981 s.y = this.el.getTop(true);
15983 var xy = this.xy || this.el.getXY();
15991 * Sets the current box measurements of the component's underlying element.
15992 * @param {Object} box An object in the format {x, y, width, height}
15993 * @returns {Roo.BoxComponent} this
15995 updateBox : function(box){
15996 this.setSize(box.width, box.height);
15997 this.setPagePosition(box.x, box.y);
16002 getResizeEl : function(){
16003 return this.resizeEl || this.el;
16007 getPositionEl : function(){
16008 return this.positionEl || this.el;
16012 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16013 * This method fires the move event.
16014 * @param {Number} left The new left
16015 * @param {Number} top The new top
16016 * @returns {Roo.BoxComponent} this
16018 setPosition : function(x, y){
16021 if(!this.boxReady){
16024 var adj = this.adjustPosition(x, y);
16025 var ax = adj.x, ay = adj.y;
16027 var el = this.getPositionEl();
16028 if(ax !== undefined || ay !== undefined){
16029 if(ax !== undefined && ay !== undefined){
16030 el.setLeftTop(ax, ay);
16031 }else if(ax !== undefined){
16033 }else if(ay !== undefined){
16036 this.onPosition(ax, ay);
16037 this.fireEvent('move', this, ax, ay);
16043 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16044 * This method fires the move event.
16045 * @param {Number} x The new x position
16046 * @param {Number} y The new y position
16047 * @returns {Roo.BoxComponent} this
16049 setPagePosition : function(x, y){
16052 if(!this.boxReady){
16055 if(x === undefined || y === undefined){ // cannot translate undefined points
16058 var p = this.el.translatePoints(x, y);
16059 this.setPosition(p.left, p.top);
16064 onRender : function(ct, position){
16065 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16067 this.resizeEl = Roo.get(this.resizeEl);
16069 if(this.positionEl){
16070 this.positionEl = Roo.get(this.positionEl);
16075 afterRender : function(){
16076 Roo.BoxComponent.superclass.afterRender.call(this);
16077 this.boxReady = true;
16078 this.setSize(this.width, this.height);
16079 if(this.x || this.y){
16080 this.setPosition(this.x, this.y);
16082 if(this.pageX || this.pageY){
16083 this.setPagePosition(this.pageX, this.pageY);
16088 * Force the component's size to recalculate based on the underlying element's current height and width.
16089 * @returns {Roo.BoxComponent} this
16091 syncSize : function(){
16092 delete this.lastSize;
16093 this.setSize(this.el.getWidth(), this.el.getHeight());
16098 * Called after the component is resized, this method is empty by default but can be implemented by any
16099 * subclass that needs to perform custom logic after a resize occurs.
16100 * @param {Number} adjWidth The box-adjusted width that was set
16101 * @param {Number} adjHeight The box-adjusted height that was set
16102 * @param {Number} rawWidth The width that was originally specified
16103 * @param {Number} rawHeight The height that was originally specified
16105 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16110 * Called after the component is moved, this method is empty by default but can be implemented by any
16111 * subclass that needs to perform custom logic after a move occurs.
16112 * @param {Number} x The new x position
16113 * @param {Number} y The new y position
16115 onPosition : function(x, y){
16120 adjustSize : function(w, h){
16121 if(this.autoWidth){
16124 if(this.autoHeight){
16127 return {width : w, height: h};
16131 adjustPosition : function(x, y){
16132 return {x : x, y: y};
16136 * Ext JS Library 1.1.1
16137 * Copyright(c) 2006-2007, Ext JS, LLC.
16139 * Originally Released Under LGPL - original licence link has changed is not relivant.
16142 * <script type="text/javascript">
16147 * @extends Roo.Element
16148 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16149 * automatic maintaining of shadow/shim positions.
16150 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16151 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16152 * you can pass a string with a CSS class name. False turns off the shadow.
16153 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16154 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16155 * @cfg {String} cls CSS class to add to the element
16156 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16157 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16159 * @param {Object} config An object with config options.
16160 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16163 Roo.Layer = function(config, existingEl){
16164 config = config || {};
16165 var dh = Roo.DomHelper;
16166 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16168 this.dom = Roo.getDom(existingEl);
16171 var o = config.dh || {tag: "div", cls: "x-layer"};
16172 this.dom = dh.append(pel, o);
16175 this.addClass(config.cls);
16177 this.constrain = config.constrain !== false;
16178 this.visibilityMode = Roo.Element.VISIBILITY;
16180 this.id = this.dom.id = config.id;
16182 this.id = Roo.id(this.dom);
16184 this.zindex = config.zindex || this.getZIndex();
16185 this.position("absolute", this.zindex);
16187 this.shadowOffset = config.shadowOffset || 4;
16188 this.shadow = new Roo.Shadow({
16189 offset : this.shadowOffset,
16190 mode : config.shadow
16193 this.shadowOffset = 0;
16195 this.useShim = config.shim !== false && Roo.useShims;
16196 this.useDisplay = config.useDisplay;
16200 var supr = Roo.Element.prototype;
16202 // shims are shared among layer to keep from having 100 iframes
16205 Roo.extend(Roo.Layer, Roo.Element, {
16207 getZIndex : function(){
16208 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16211 getShim : function(){
16218 var shim = shims.shift();
16220 shim = this.createShim();
16221 shim.enableDisplayMode('block');
16222 shim.dom.style.display = 'none';
16223 shim.dom.style.visibility = 'visible';
16225 var pn = this.dom.parentNode;
16226 if(shim.dom.parentNode != pn){
16227 pn.insertBefore(shim.dom, this.dom);
16229 shim.setStyle('z-index', this.getZIndex()-2);
16234 hideShim : function(){
16236 this.shim.setDisplayed(false);
16237 shims.push(this.shim);
16242 disableShadow : function(){
16244 this.shadowDisabled = true;
16245 this.shadow.hide();
16246 this.lastShadowOffset = this.shadowOffset;
16247 this.shadowOffset = 0;
16251 enableShadow : function(show){
16253 this.shadowDisabled = false;
16254 this.shadowOffset = this.lastShadowOffset;
16255 delete this.lastShadowOffset;
16263 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16264 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16265 sync : function(doShow){
16266 var sw = this.shadow;
16267 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16268 var sh = this.getShim();
16270 var w = this.getWidth(),
16271 h = this.getHeight();
16273 var l = this.getLeft(true),
16274 t = this.getTop(true);
16276 if(sw && !this.shadowDisabled){
16277 if(doShow && !sw.isVisible()){
16280 sw.realign(l, t, w, h);
16286 // fit the shim behind the shadow, so it is shimmed too
16287 var a = sw.adjusts, s = sh.dom.style;
16288 s.left = (Math.min(l, l+a.l))+"px";
16289 s.top = (Math.min(t, t+a.t))+"px";
16290 s.width = (w+a.w)+"px";
16291 s.height = (h+a.h)+"px";
16298 sh.setLeftTop(l, t);
16305 destroy : function(){
16308 this.shadow.hide();
16310 this.removeAllListeners();
16311 var pn = this.dom.parentNode;
16313 pn.removeChild(this.dom);
16315 Roo.Element.uncache(this.id);
16318 remove : function(){
16323 beginUpdate : function(){
16324 this.updating = true;
16328 endUpdate : function(){
16329 this.updating = false;
16334 hideUnders : function(negOffset){
16336 this.shadow.hide();
16342 constrainXY : function(){
16343 if(this.constrain){
16344 var vw = Roo.lib.Dom.getViewWidth(),
16345 vh = Roo.lib.Dom.getViewHeight();
16346 var s = Roo.get(document).getScroll();
16348 var xy = this.getXY();
16349 var x = xy[0], y = xy[1];
16350 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16351 // only move it if it needs it
16353 // first validate right/bottom
16354 if((x + w) > vw+s.left){
16355 x = vw - w - this.shadowOffset;
16358 if((y + h) > vh+s.top){
16359 y = vh - h - this.shadowOffset;
16362 // then make sure top/left isn't negative
16373 var ay = this.avoidY;
16374 if(y <= ay && (y+h) >= ay){
16380 supr.setXY.call(this, xy);
16386 isVisible : function(){
16387 return this.visible;
16391 showAction : function(){
16392 this.visible = true; // track visibility to prevent getStyle calls
16393 if(this.useDisplay === true){
16394 this.setDisplayed("");
16395 }else if(this.lastXY){
16396 supr.setXY.call(this, this.lastXY);
16397 }else if(this.lastLT){
16398 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16403 hideAction : function(){
16404 this.visible = false;
16405 if(this.useDisplay === true){
16406 this.setDisplayed(false);
16408 this.setLeftTop(-10000,-10000);
16412 // overridden Element method
16413 setVisible : function(v, a, d, c, e){
16418 var cb = function(){
16423 }.createDelegate(this);
16424 supr.setVisible.call(this, true, true, d, cb, e);
16427 this.hideUnders(true);
16436 }.createDelegate(this);
16438 supr.setVisible.call(this, v, a, d, cb, e);
16447 storeXY : function(xy){
16448 delete this.lastLT;
16452 storeLeftTop : function(left, top){
16453 delete this.lastXY;
16454 this.lastLT = [left, top];
16458 beforeFx : function(){
16459 this.beforeAction();
16460 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16464 afterFx : function(){
16465 Roo.Layer.superclass.afterFx.apply(this, arguments);
16466 this.sync(this.isVisible());
16470 beforeAction : function(){
16471 if(!this.updating && this.shadow){
16472 this.shadow.hide();
16476 // overridden Element method
16477 setLeft : function(left){
16478 this.storeLeftTop(left, this.getTop(true));
16479 supr.setLeft.apply(this, arguments);
16483 setTop : function(top){
16484 this.storeLeftTop(this.getLeft(true), top);
16485 supr.setTop.apply(this, arguments);
16489 setLeftTop : function(left, top){
16490 this.storeLeftTop(left, top);
16491 supr.setLeftTop.apply(this, arguments);
16495 setXY : function(xy, a, d, c, e){
16497 this.beforeAction();
16499 var cb = this.createCB(c);
16500 supr.setXY.call(this, xy, a, d, cb, e);
16507 createCB : function(c){
16518 // overridden Element method
16519 setX : function(x, a, d, c, e){
16520 this.setXY([x, this.getY()], a, d, c, e);
16523 // overridden Element method
16524 setY : function(y, a, d, c, e){
16525 this.setXY([this.getX(), y], a, d, c, e);
16528 // overridden Element method
16529 setSize : function(w, h, a, d, c, e){
16530 this.beforeAction();
16531 var cb = this.createCB(c);
16532 supr.setSize.call(this, w, h, a, d, cb, e);
16538 // overridden Element method
16539 setWidth : function(w, a, d, c, e){
16540 this.beforeAction();
16541 var cb = this.createCB(c);
16542 supr.setWidth.call(this, w, a, d, cb, e);
16548 // overridden Element method
16549 setHeight : function(h, a, d, c, e){
16550 this.beforeAction();
16551 var cb = this.createCB(c);
16552 supr.setHeight.call(this, h, a, d, cb, e);
16558 // overridden Element method
16559 setBounds : function(x, y, w, h, a, d, c, e){
16560 this.beforeAction();
16561 var cb = this.createCB(c);
16563 this.storeXY([x, y]);
16564 supr.setXY.call(this, [x, y]);
16565 supr.setSize.call(this, w, h, a, d, cb, e);
16568 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16574 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16575 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16576 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16577 * @param {Number} zindex The new z-index to set
16578 * @return {this} The Layer
16580 setZIndex : function(zindex){
16581 this.zindex = zindex;
16582 this.setStyle("z-index", zindex + 2);
16584 this.shadow.setZIndex(zindex + 1);
16587 this.shim.setStyle("z-index", zindex);
16592 * Original code for Roojs - LGPL
16593 * <script type="text/javascript">
16597 * @class Roo.XComponent
16598 * A delayed Element creator...
16599 * Or a way to group chunks of interface together.
16600 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16601 * used in conjunction with XComponent.build() it will create an instance of each element,
16602 * then call addxtype() to build the User interface.
16604 * Mypart.xyx = new Roo.XComponent({
16606 parent : 'Mypart.xyz', // empty == document.element.!!
16610 disabled : function() {}
16612 tree : function() { // return an tree of xtype declared components
16616 xtype : 'NestedLayoutPanel',
16623 * It can be used to build a big heiracy, with parent etc.
16624 * or you can just use this to render a single compoent to a dom element
16625 * MYPART.render(Roo.Element | String(id) | dom_element )
16632 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16633 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16635 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16637 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16638 * - if mulitple topModules exist, the last one is defined as the top module.
16642 * When the top level or multiple modules are to embedded into a existing HTML page,
16643 * the parent element can container '#id' of the element where the module will be drawn.
16647 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16648 * it relies more on a include mechanism, where sub modules are included into an outer page.
16649 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16651 * Bootstrap Roo Included elements
16653 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16654 * hence confusing the component builder as it thinks there are multiple top level elements.
16656 * String Over-ride & Translations
16658 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16659 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16660 * are needed. @see Roo.XComponent.overlayString
16664 * @extends Roo.util.Observable
16666 * @param cfg {Object} configuration of component
16669 Roo.XComponent = function(cfg) {
16670 Roo.apply(this, cfg);
16674 * Fires when this the componnt is built
16675 * @param {Roo.XComponent} c the component
16680 this.region = this.region || 'center'; // default..
16681 Roo.XComponent.register(this);
16682 this.modules = false;
16683 this.el = false; // where the layout goes..
16687 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16690 * The created element (with Roo.factory())
16691 * @type {Roo.Layout}
16697 * for BC - use el in new code
16698 * @type {Roo.Layout}
16704 * for BC - use el in new code
16705 * @type {Roo.Layout}
16710 * @cfg {Function|boolean} disabled
16711 * If this module is disabled by some rule, return true from the funtion
16716 * @cfg {String} parent
16717 * Name of parent element which it get xtype added to..
16722 * @cfg {String} order
16723 * Used to set the order in which elements are created (usefull for multiple tabs)
16728 * @cfg {String} name
16729 * String to display while loading.
16733 * @cfg {String} region
16734 * Region to render component to (defaults to center)
16739 * @cfg {Array} items
16740 * A single item array - the first element is the root of the tree..
16741 * It's done this way to stay compatible with the Xtype system...
16747 * The method that retuns the tree of parts that make up this compoennt
16754 * render element to dom or tree
16755 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16758 render : function(el)
16762 var hp = this.parent ? 1 : 0;
16763 Roo.debug && Roo.log(this);
16765 var tree = this._tree ? this._tree() : this.tree();
16768 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16769 // if parent is a '#.....' string, then let's use that..
16770 var ename = this.parent.substr(1);
16771 this.parent = false;
16772 Roo.debug && Roo.log(ename);
16774 case 'bootstrap-body':
16775 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16776 // this is the BorderLayout standard?
16777 this.parent = { el : true };
16780 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16781 // need to insert stuff...
16783 el : new Roo.bootstrap.layout.Border({
16784 el : document.body,
16790 tabPosition: 'top',
16791 //resizeTabs: true,
16792 alwaysShowTabs: true,
16802 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16803 this.parent = { el : new Roo.bootstrap.Body() };
16804 Roo.debug && Roo.log("setting el to doc body");
16807 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16811 this.parent = { el : true};
16814 el = Roo.get(ename);
16815 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16816 this.parent = { el : true};
16823 if (!el && !this.parent) {
16824 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16829 Roo.debug && Roo.log("EL:");
16830 Roo.debug && Roo.log(el);
16831 Roo.debug && Roo.log("this.parent.el:");
16832 Roo.debug && Roo.log(this.parent.el);
16835 // altertive root elements ??? - we need a better way to indicate these.
16836 var is_alt = Roo.XComponent.is_alt ||
16837 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16838 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16839 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16843 if (!this.parent && is_alt) {
16844 //el = Roo.get(document.body);
16845 this.parent = { el : true };
16850 if (!this.parent) {
16852 Roo.debug && Roo.log("no parent - creating one");
16854 el = el ? Roo.get(el) : false;
16856 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16859 el : new Roo.bootstrap.layout.Border({
16860 el: el || document.body,
16866 tabPosition: 'top',
16867 //resizeTabs: true,
16868 alwaysShowTabs: false,
16871 overflow: 'visible'
16877 // it's a top level one..
16879 el : new Roo.BorderLayout(el || document.body, {
16884 tabPosition: 'top',
16885 //resizeTabs: true,
16886 alwaysShowTabs: el && hp? false : true,
16887 hideTabs: el || !hp ? true : false,
16895 if (!this.parent.el) {
16896 // probably an old style ctor, which has been disabled.
16900 // The 'tree' method is '_tree now'
16902 tree.region = tree.region || this.region;
16903 var is_body = false;
16904 if (this.parent.el === true) {
16905 // bootstrap... - body..
16909 this.parent.el = Roo.factory(tree);
16913 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16914 this.fireEvent('built', this);
16916 this.panel = this.el;
16917 this.layout = this.panel.layout;
16918 this.parentLayout = this.parent.layout || false;
16924 Roo.apply(Roo.XComponent, {
16926 * @property hideProgress
16927 * true to disable the building progress bar.. usefull on single page renders.
16930 hideProgress : false,
16932 * @property buildCompleted
16933 * True when the builder has completed building the interface.
16936 buildCompleted : false,
16939 * @property topModule
16940 * the upper most module - uses document.element as it's constructor.
16947 * @property modules
16948 * array of modules to be created by registration system.
16949 * @type {Array} of Roo.XComponent
16954 * @property elmodules
16955 * array of modules to be created by which use #ID
16956 * @type {Array} of Roo.XComponent
16963 * Is an alternative Root - normally used by bootstrap or other systems,
16964 * where the top element in the tree can wrap 'body'
16965 * @type {boolean} (default false)
16970 * @property build_from_html
16971 * Build elements from html - used by bootstrap HTML stuff
16972 * - this is cleared after build is completed
16973 * @type {boolean} (default false)
16976 build_from_html : false,
16978 * Register components to be built later.
16980 * This solves the following issues
16981 * - Building is not done on page load, but after an authentication process has occured.
16982 * - Interface elements are registered on page load
16983 * - Parent Interface elements may not be loaded before child, so this handles that..
16990 module : 'Pman.Tab.projectMgr',
16992 parent : 'Pman.layout',
16993 disabled : false, // or use a function..
16996 * * @param {Object} details about module
16998 register : function(obj) {
17000 Roo.XComponent.event.fireEvent('register', obj);
17001 switch(typeof(obj.disabled) ) {
17007 if ( obj.disabled() ) {
17013 if (obj.disabled || obj.region == '#disabled') {
17019 this.modules.push(obj);
17023 * convert a string to an object..
17024 * eg. 'AAA.BBB' -> finds AAA.BBB
17028 toObject : function(str)
17030 if (!str || typeof(str) == 'object') {
17033 if (str.substring(0,1) == '#') {
17037 var ar = str.split('.');
17042 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17044 throw "Module not found : " + str;
17048 throw "Module not found : " + str;
17050 Roo.each(ar, function(e) {
17051 if (typeof(o[e]) == 'undefined') {
17052 throw "Module not found : " + str;
17063 * move modules into their correct place in the tree..
17066 preBuild : function ()
17069 Roo.each(this.modules , function (obj)
17071 Roo.XComponent.event.fireEvent('beforebuild', obj);
17073 var opar = obj.parent;
17075 obj.parent = this.toObject(opar);
17077 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17082 Roo.debug && Roo.log("GOT top level module");
17083 Roo.debug && Roo.log(obj);
17084 obj.modules = new Roo.util.MixedCollection(false,
17085 function(o) { return o.order + '' }
17087 this.topModule = obj;
17090 // parent is a string (usually a dom element name..)
17091 if (typeof(obj.parent) == 'string') {
17092 this.elmodules.push(obj);
17095 if (obj.parent.constructor != Roo.XComponent) {
17096 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17098 if (!obj.parent.modules) {
17099 obj.parent.modules = new Roo.util.MixedCollection(false,
17100 function(o) { return o.order + '' }
17103 if (obj.parent.disabled) {
17104 obj.disabled = true;
17106 obj.parent.modules.add(obj);
17111 * make a list of modules to build.
17112 * @return {Array} list of modules.
17115 buildOrder : function()
17118 var cmp = function(a,b) {
17119 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17121 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17122 throw "No top level modules to build";
17125 // make a flat list in order of modules to build.
17126 var mods = this.topModule ? [ this.topModule ] : [];
17129 // elmodules (is a list of DOM based modules )
17130 Roo.each(this.elmodules, function(e) {
17132 if (!this.topModule &&
17133 typeof(e.parent) == 'string' &&
17134 e.parent.substring(0,1) == '#' &&
17135 Roo.get(e.parent.substr(1))
17138 _this.topModule = e;
17144 // add modules to their parents..
17145 var addMod = function(m) {
17146 Roo.debug && Roo.log("build Order: add: " + m.name);
17149 if (m.modules && !m.disabled) {
17150 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17151 m.modules.keySort('ASC', cmp );
17152 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17154 m.modules.each(addMod);
17156 Roo.debug && Roo.log("build Order: no child modules");
17158 // not sure if this is used any more..
17160 m.finalize.name = m.name + " (clean up) ";
17161 mods.push(m.finalize);
17165 if (this.topModule && this.topModule.modules) {
17166 this.topModule.modules.keySort('ASC', cmp );
17167 this.topModule.modules.each(addMod);
17173 * Build the registered modules.
17174 * @param {Object} parent element.
17175 * @param {Function} optional method to call after module has been added.
17179 build : function(opts)
17182 if (typeof(opts) != 'undefined') {
17183 Roo.apply(this,opts);
17187 var mods = this.buildOrder();
17189 //this.allmods = mods;
17190 //Roo.debug && Roo.log(mods);
17192 if (!mods.length) { // should not happen
17193 throw "NO modules!!!";
17197 var msg = "Building Interface...";
17198 // flash it up as modal - so we store the mask!?
17199 if (!this.hideProgress && Roo.MessageBox) {
17200 Roo.MessageBox.show({ title: 'loading' });
17201 Roo.MessageBox.show({
17202 title: "Please wait...",
17212 var total = mods.length;
17215 var progressRun = function() {
17216 if (!mods.length) {
17217 Roo.debug && Roo.log('hide?');
17218 if (!this.hideProgress && Roo.MessageBox) {
17219 Roo.MessageBox.hide();
17221 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17223 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17229 var m = mods.shift();
17232 Roo.debug && Roo.log(m);
17233 // not sure if this is supported any more.. - modules that are are just function
17234 if (typeof(m) == 'function') {
17236 return progressRun.defer(10, _this);
17240 msg = "Building Interface " + (total - mods.length) +
17242 (m.name ? (' - ' + m.name) : '');
17243 Roo.debug && Roo.log(msg);
17244 if (!_this.hideProgress && Roo.MessageBox) {
17245 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17249 // is the module disabled?
17250 var disabled = (typeof(m.disabled) == 'function') ?
17251 m.disabled.call(m.module.disabled) : m.disabled;
17255 return progressRun(); // we do not update the display!
17263 // it's 10 on top level, and 1 on others??? why...
17264 return progressRun.defer(10, _this);
17267 progressRun.defer(1, _this);
17273 * Overlay a set of modified strings onto a component
17274 * This is dependant on our builder exporting the strings and 'named strings' elements.
17276 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17277 * @param {Object} associative array of 'named' string and it's new value.
17280 overlayStrings : function( component, strings )
17282 if (typeof(component['_named_strings']) == 'undefined') {
17283 throw "ERROR: component does not have _named_strings";
17285 for ( var k in strings ) {
17286 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17287 if (md !== false) {
17288 component['_strings'][md] = strings[k];
17290 Roo.log('could not find named string: ' + k + ' in');
17291 Roo.log(component);
17306 * wrapper for event.on - aliased later..
17307 * Typically use to register a event handler for register:
17309 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17318 Roo.XComponent.event = new Roo.util.Observable({
17322 * Fires when an Component is registered,
17323 * set the disable property on the Component to stop registration.
17324 * @param {Roo.XComponent} c the component being registerd.
17329 * @event beforebuild
17330 * Fires before each Component is built
17331 * can be used to apply permissions.
17332 * @param {Roo.XComponent} c the component being registerd.
17335 'beforebuild' : true,
17337 * @event buildcomplete
17338 * Fires on the top level element when all elements have been built
17339 * @param {Roo.XComponent} the top level component.
17341 'buildcomplete' : true
17346 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17349 * marked - a markdown parser
17350 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17351 * https://github.com/chjj/marked
17357 * Roo.Markdown - is a very crude wrapper around marked..
17361 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17363 * Note: move the sample code to the bottom of this
17364 * file before uncommenting it.
17369 Roo.Markdown.toHtml = function(text) {
17371 var c = new Roo.Markdown.marked.setOptions({
17372 renderer: new Roo.Markdown.marked.Renderer(),
17383 text = text.replace(/\\\n/g,' ');
17384 return Roo.Markdown.marked(text);
17389 // Wraps all "globals" so that the only thing
17390 // exposed is makeHtml().
17396 * eval:var:unescape
17404 var escape = function (html, encode) {
17406 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17407 .replace(/</g, '<')
17408 .replace(/>/g, '>')
17409 .replace(/"/g, '"')
17410 .replace(/'/g, ''');
17413 var unescape = function (html) {
17414 // explicitly match decimal, hex, and named HTML entities
17415 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17416 n = n.toLowerCase();
17417 if (n === 'colon') { return ':'; }
17418 if (n.charAt(0) === '#') {
17419 return n.charAt(1) === 'x'
17420 ? String.fromCharCode(parseInt(n.substring(2), 16))
17421 : String.fromCharCode(+n.substring(1));
17427 var replace = function (regex, opt) {
17428 regex = regex.source;
17430 return function self(name, val) {
17431 if (!name) { return new RegExp(regex, opt); }
17432 val = val.source || val;
17433 val = val.replace(/(^|[^\[])\^/g, '$1');
17434 regex = regex.replace(name, val);
17443 var noop = function () {}
17449 var merge = function (obj) {
17454 for (; i < arguments.length; i++) {
17455 target = arguments[i];
17456 for (key in target) {
17457 if (Object.prototype.hasOwnProperty.call(target, key)) {
17458 obj[key] = target[key];
17468 * Block-Level Grammar
17476 code: /^( {4}[^\n]+\n*)+/,
17478 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17479 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17481 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17482 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17483 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17484 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17485 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17487 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17491 block.bullet = /(?:[*+-]|\d+\.)/;
17492 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17493 block.item = replace(block.item, 'gm')
17494 (/bull/g, block.bullet)
17497 block.list = replace(block.list)
17498 (/bull/g, block.bullet)
17499 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17500 ('def', '\\n+(?=' + block.def.source + ')')
17503 block.blockquote = replace(block.blockquote)
17507 block._tag = '(?!(?:'
17508 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17509 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17510 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17512 block.html = replace(block.html)
17513 ('comment', /<!--[\s\S]*?-->/)
17514 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17515 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17516 (/tag/g, block._tag)
17519 block.paragraph = replace(block.paragraph)
17521 ('heading', block.heading)
17522 ('lheading', block.lheading)
17523 ('blockquote', block.blockquote)
17524 ('tag', '<' + block._tag)
17529 * Normal Block Grammar
17532 block.normal = merge({}, block);
17535 * GFM Block Grammar
17538 block.gfm = merge({}, block.normal, {
17539 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17541 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17544 block.gfm.paragraph = replace(block.paragraph)
17546 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17547 + block.list.source.replace('\\1', '\\3') + '|')
17551 * GFM + Tables Block Grammar
17554 block.tables = merge({}, block.gfm, {
17555 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17556 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17563 var Lexer = function (options) {
17565 this.tokens.links = {};
17566 this.options = options || marked.defaults;
17567 this.rules = block.normal;
17569 if (this.options.gfm) {
17570 if (this.options.tables) {
17571 this.rules = block.tables;
17573 this.rules = block.gfm;
17579 * Expose Block Rules
17582 Lexer.rules = block;
17585 * Static Lex Method
17588 Lexer.lex = function(src, options) {
17589 var lexer = new Lexer(options);
17590 return lexer.lex(src);
17597 Lexer.prototype.lex = function(src) {
17599 .replace(/\r\n|\r/g, '\n')
17600 .replace(/\t/g, ' ')
17601 .replace(/\u00a0/g, ' ')
17602 .replace(/\u2424/g, '\n');
17604 return this.token(src, true);
17611 Lexer.prototype.token = function(src, top, bq) {
17612 var src = src.replace(/^ +$/gm, '')
17625 if (cap = this.rules.newline.exec(src)) {
17626 src = src.substring(cap[0].length);
17627 if (cap[0].length > 1) {
17635 if (cap = this.rules.code.exec(src)) {
17636 src = src.substring(cap[0].length);
17637 cap = cap[0].replace(/^ {4}/gm, '');
17640 text: !this.options.pedantic
17641 ? cap.replace(/\n+$/, '')
17648 if (cap = this.rules.fences.exec(src)) {
17649 src = src.substring(cap[0].length);
17659 if (cap = this.rules.heading.exec(src)) {
17660 src = src.substring(cap[0].length);
17663 depth: cap[1].length,
17669 // table no leading pipe (gfm)
17670 if (top && (cap = this.rules.nptable.exec(src))) {
17671 src = src.substring(cap[0].length);
17675 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17676 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17677 cells: cap[3].replace(/\n$/, '').split('\n')
17680 for (i = 0; i < item.align.length; i++) {
17681 if (/^ *-+: *$/.test(item.align[i])) {
17682 item.align[i] = 'right';
17683 } else if (/^ *:-+: *$/.test(item.align[i])) {
17684 item.align[i] = 'center';
17685 } else if (/^ *:-+ *$/.test(item.align[i])) {
17686 item.align[i] = 'left';
17688 item.align[i] = null;
17692 for (i = 0; i < item.cells.length; i++) {
17693 item.cells[i] = item.cells[i].split(/ *\| */);
17696 this.tokens.push(item);
17702 if (cap = this.rules.lheading.exec(src)) {
17703 src = src.substring(cap[0].length);
17706 depth: cap[2] === '=' ? 1 : 2,
17713 if (cap = this.rules.hr.exec(src)) {
17714 src = src.substring(cap[0].length);
17722 if (cap = this.rules.blockquote.exec(src)) {
17723 src = src.substring(cap[0].length);
17726 type: 'blockquote_start'
17729 cap = cap[0].replace(/^ *> ?/gm, '');
17731 // Pass `top` to keep the current
17732 // "toplevel" state. This is exactly
17733 // how markdown.pl works.
17734 this.token(cap, top, true);
17737 type: 'blockquote_end'
17744 if (cap = this.rules.list.exec(src)) {
17745 src = src.substring(cap[0].length);
17749 type: 'list_start',
17750 ordered: bull.length > 1
17753 // Get each top-level item.
17754 cap = cap[0].match(this.rules.item);
17760 for (; i < l; i++) {
17763 // Remove the list item's bullet
17764 // so it is seen as the next token.
17765 space = item.length;
17766 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17768 // Outdent whatever the
17769 // list item contains. Hacky.
17770 if (~item.indexOf('\n ')) {
17771 space -= item.length;
17772 item = !this.options.pedantic
17773 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17774 : item.replace(/^ {1,4}/gm, '');
17777 // Determine whether the next list item belongs here.
17778 // Backpedal if it does not belong in this list.
17779 if (this.options.smartLists && i !== l - 1) {
17780 b = block.bullet.exec(cap[i + 1])[0];
17781 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17782 src = cap.slice(i + 1).join('\n') + src;
17787 // Determine whether item is loose or not.
17788 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17789 // for discount behavior.
17790 loose = next || /\n\n(?!\s*$)/.test(item);
17792 next = item.charAt(item.length - 1) === '\n';
17793 if (!loose) { loose = next; }
17798 ? 'loose_item_start'
17799 : 'list_item_start'
17803 this.token(item, false, bq);
17806 type: 'list_item_end'
17818 if (cap = this.rules.html.exec(src)) {
17819 src = src.substring(cap[0].length);
17821 type: this.options.sanitize
17824 pre: !this.options.sanitizer
17825 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17832 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17833 src = src.substring(cap[0].length);
17834 this.tokens.links[cap[1].toLowerCase()] = {
17842 if (top && (cap = this.rules.table.exec(src))) {
17843 src = src.substring(cap[0].length);
17847 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17848 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17849 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17852 for (i = 0; i < item.align.length; i++) {
17853 if (/^ *-+: *$/.test(item.align[i])) {
17854 item.align[i] = 'right';
17855 } else if (/^ *:-+: *$/.test(item.align[i])) {
17856 item.align[i] = 'center';
17857 } else if (/^ *:-+ *$/.test(item.align[i])) {
17858 item.align[i] = 'left';
17860 item.align[i] = null;
17864 for (i = 0; i < item.cells.length; i++) {
17865 item.cells[i] = item.cells[i]
17866 .replace(/^ *\| *| *\| *$/g, '')
17870 this.tokens.push(item);
17875 // top-level paragraph
17876 if (top && (cap = this.rules.paragraph.exec(src))) {
17877 src = src.substring(cap[0].length);
17880 text: cap[1].charAt(cap[1].length - 1) === '\n'
17881 ? cap[1].slice(0, -1)
17888 if (cap = this.rules.text.exec(src)) {
17889 // Top-level should never reach here.
17890 src = src.substring(cap[0].length);
17900 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17904 return this.tokens;
17908 * Inline-Level Grammar
17912 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17913 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17915 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17916 link: /^!?\[(inside)\]\(href\)/,
17917 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17918 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17919 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17920 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17921 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17922 br: /^ {2,}\n(?!\s*$)/,
17924 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17927 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17928 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17930 inline.link = replace(inline.link)
17931 ('inside', inline._inside)
17932 ('href', inline._href)
17935 inline.reflink = replace(inline.reflink)
17936 ('inside', inline._inside)
17940 * Normal Inline Grammar
17943 inline.normal = merge({}, inline);
17946 * Pedantic Inline Grammar
17949 inline.pedantic = merge({}, inline.normal, {
17950 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17951 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17955 * GFM Inline Grammar
17958 inline.gfm = merge({}, inline.normal, {
17959 escape: replace(inline.escape)('])', '~|])')(),
17960 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17961 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17962 text: replace(inline.text)
17964 ('|', '|https?://|')
17969 * GFM + Line Breaks Inline Grammar
17972 inline.breaks = merge({}, inline.gfm, {
17973 br: replace(inline.br)('{2,}', '*')(),
17974 text: replace(inline.gfm.text)('{2,}', '*')()
17978 * Inline Lexer & Compiler
17981 var InlineLexer = function (links, options) {
17982 this.options = options || marked.defaults;
17983 this.links = links;
17984 this.rules = inline.normal;
17985 this.renderer = this.options.renderer || new Renderer;
17986 this.renderer.options = this.options;
17990 Error('Tokens array requires a `links` property.');
17993 if (this.options.gfm) {
17994 if (this.options.breaks) {
17995 this.rules = inline.breaks;
17997 this.rules = inline.gfm;
17999 } else if (this.options.pedantic) {
18000 this.rules = inline.pedantic;
18005 * Expose Inline Rules
18008 InlineLexer.rules = inline;
18011 * Static Lexing/Compiling Method
18014 InlineLexer.output = function(src, links, options) {
18015 var inline = new InlineLexer(links, options);
18016 return inline.output(src);
18023 InlineLexer.prototype.output = function(src) {
18032 if (cap = this.rules.escape.exec(src)) {
18033 src = src.substring(cap[0].length);
18039 if (cap = this.rules.autolink.exec(src)) {
18040 src = src.substring(cap[0].length);
18041 if (cap[2] === '@') {
18042 text = cap[1].charAt(6) === ':'
18043 ? this.mangle(cap[1].substring(7))
18044 : this.mangle(cap[1]);
18045 href = this.mangle('mailto:') + text;
18047 text = escape(cap[1]);
18050 out += this.renderer.link(href, null, text);
18055 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18056 src = src.substring(cap[0].length);
18057 text = escape(cap[1]);
18059 out += this.renderer.link(href, null, text);
18064 if (cap = this.rules.tag.exec(src)) {
18065 if (!this.inLink && /^<a /i.test(cap[0])) {
18066 this.inLink = true;
18067 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18068 this.inLink = false;
18070 src = src.substring(cap[0].length);
18071 out += this.options.sanitize
18072 ? this.options.sanitizer
18073 ? this.options.sanitizer(cap[0])
18080 if (cap = this.rules.link.exec(src)) {
18081 src = src.substring(cap[0].length);
18082 this.inLink = true;
18083 out += this.outputLink(cap, {
18087 this.inLink = false;
18092 if ((cap = this.rules.reflink.exec(src))
18093 || (cap = this.rules.nolink.exec(src))) {
18094 src = src.substring(cap[0].length);
18095 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18096 link = this.links[link.toLowerCase()];
18097 if (!link || !link.href) {
18098 out += cap[0].charAt(0);
18099 src = cap[0].substring(1) + src;
18102 this.inLink = true;
18103 out += this.outputLink(cap, link);
18104 this.inLink = false;
18109 if (cap = this.rules.strong.exec(src)) {
18110 src = src.substring(cap[0].length);
18111 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18116 if (cap = this.rules.em.exec(src)) {
18117 src = src.substring(cap[0].length);
18118 out += this.renderer.em(this.output(cap[2] || cap[1]));
18123 if (cap = this.rules.code.exec(src)) {
18124 src = src.substring(cap[0].length);
18125 out += this.renderer.codespan(escape(cap[2], true));
18130 if (cap = this.rules.br.exec(src)) {
18131 src = src.substring(cap[0].length);
18132 out += this.renderer.br();
18137 if (cap = this.rules.del.exec(src)) {
18138 src = src.substring(cap[0].length);
18139 out += this.renderer.del(this.output(cap[1]));
18144 if (cap = this.rules.text.exec(src)) {
18145 src = src.substring(cap[0].length);
18146 out += this.renderer.text(escape(this.smartypants(cap[0])));
18152 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18163 InlineLexer.prototype.outputLink = function(cap, link) {
18164 var href = escape(link.href)
18165 , title = link.title ? escape(link.title) : null;
18167 return cap[0].charAt(0) !== '!'
18168 ? this.renderer.link(href, title, this.output(cap[1]))
18169 : this.renderer.image(href, title, escape(cap[1]));
18173 * Smartypants Transformations
18176 InlineLexer.prototype.smartypants = function(text) {
18177 if (!this.options.smartypants) { return text; }
18180 .replace(/---/g, '\u2014')
18182 .replace(/--/g, '\u2013')
18184 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18185 // closing singles & apostrophes
18186 .replace(/'/g, '\u2019')
18188 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18190 .replace(/"/g, '\u201d')
18192 .replace(/\.{3}/g, '\u2026');
18199 InlineLexer.prototype.mangle = function(text) {
18200 if (!this.options.mangle) { return text; }
18206 for (; i < l; i++) {
18207 ch = text.charCodeAt(i);
18208 if (Math.random() > 0.5) {
18209 ch = 'x' + ch.toString(16);
18211 out += '&#' + ch + ';';
18222 * eval:var:Renderer
18225 var Renderer = function (options) {
18226 this.options = options || {};
18229 Renderer.prototype.code = function(code, lang, escaped) {
18230 if (this.options.highlight) {
18231 var out = this.options.highlight(code, lang);
18232 if (out != null && out !== code) {
18237 // hack!!! - it's already escapeD?
18242 return '<pre><code>'
18243 + (escaped ? code : escape(code, true))
18244 + '\n</code></pre>';
18247 return '<pre><code class="'
18248 + this.options.langPrefix
18249 + escape(lang, true)
18251 + (escaped ? code : escape(code, true))
18252 + '\n</code></pre>\n';
18255 Renderer.prototype.blockquote = function(quote) {
18256 return '<blockquote>\n' + quote + '</blockquote>\n';
18259 Renderer.prototype.html = function(html) {
18263 Renderer.prototype.heading = function(text, level, raw) {
18267 + this.options.headerPrefix
18268 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18276 Renderer.prototype.hr = function() {
18277 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18280 Renderer.prototype.list = function(body, ordered) {
18281 var type = ordered ? 'ol' : 'ul';
18282 return '<' + type + '>\n' + body + '</' + type + '>\n';
18285 Renderer.prototype.listitem = function(text) {
18286 return '<li>' + text + '</li>\n';
18289 Renderer.prototype.paragraph = function(text) {
18290 return '<p>' + text + '</p>\n';
18293 Renderer.prototype.table = function(header, body) {
18294 return '<table class="table table-striped">\n'
18304 Renderer.prototype.tablerow = function(content) {
18305 return '<tr>\n' + content + '</tr>\n';
18308 Renderer.prototype.tablecell = function(content, flags) {
18309 var type = flags.header ? 'th' : 'td';
18310 var tag = flags.align
18311 ? '<' + type + ' style="text-align:' + flags.align + '">'
18312 : '<' + type + '>';
18313 return tag + content + '</' + type + '>\n';
18316 // span level renderer
18317 Renderer.prototype.strong = function(text) {
18318 return '<strong>' + text + '</strong>';
18321 Renderer.prototype.em = function(text) {
18322 return '<em>' + text + '</em>';
18325 Renderer.prototype.codespan = function(text) {
18326 return '<code>' + text + '</code>';
18329 Renderer.prototype.br = function() {
18330 return this.options.xhtml ? '<br/>' : '<br>';
18333 Renderer.prototype.del = function(text) {
18334 return '<del>' + text + '</del>';
18337 Renderer.prototype.link = function(href, title, text) {
18338 if (this.options.sanitize) {
18340 var prot = decodeURIComponent(unescape(href))
18341 .replace(/[^\w:]/g, '')
18346 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18350 var out = '<a href="' + href + '"';
18352 out += ' title="' + title + '"';
18354 out += '>' + text + '</a>';
18358 Renderer.prototype.image = function(href, title, text) {
18359 var out = '<img src="' + href + '" alt="' + text + '"';
18361 out += ' title="' + title + '"';
18363 out += this.options.xhtml ? '/>' : '>';
18367 Renderer.prototype.text = function(text) {
18372 * Parsing & Compiling
18378 var Parser= function (options) {
18381 this.options = options || marked.defaults;
18382 this.options.renderer = this.options.renderer || new Renderer;
18383 this.renderer = this.options.renderer;
18384 this.renderer.options = this.options;
18388 * Static Parse Method
18391 Parser.parse = function(src, options, renderer) {
18392 var parser = new Parser(options, renderer);
18393 return parser.parse(src);
18400 Parser.prototype.parse = function(src) {
18401 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18402 this.tokens = src.reverse();
18405 while (this.next()) {
18416 Parser.prototype.next = function() {
18417 return this.token = this.tokens.pop();
18421 * Preview Next Token
18424 Parser.prototype.peek = function() {
18425 return this.tokens[this.tokens.length - 1] || 0;
18429 * Parse Text Tokens
18432 Parser.prototype.parseText = function() {
18433 var body = this.token.text;
18435 while (this.peek().type === 'text') {
18436 body += '\n' + this.next().text;
18439 return this.inline.output(body);
18443 * Parse Current Token
18446 Parser.prototype.tok = function() {
18447 switch (this.token.type) {
18452 return this.renderer.hr();
18455 return this.renderer.heading(
18456 this.inline.output(this.token.text),
18461 return this.renderer.code(this.token.text,
18463 this.token.escaped);
18476 for (i = 0; i < this.token.header.length; i++) {
18477 flags = { header: true, align: this.token.align[i] };
18478 cell += this.renderer.tablecell(
18479 this.inline.output(this.token.header[i]),
18480 { header: true, align: this.token.align[i] }
18483 header += this.renderer.tablerow(cell);
18485 for (i = 0; i < this.token.cells.length; i++) {
18486 row = this.token.cells[i];
18489 for (j = 0; j < row.length; j++) {
18490 cell += this.renderer.tablecell(
18491 this.inline.output(row[j]),
18492 { header: false, align: this.token.align[j] }
18496 body += this.renderer.tablerow(cell);
18498 return this.renderer.table(header, body);
18500 case 'blockquote_start': {
18503 while (this.next().type !== 'blockquote_end') {
18504 body += this.tok();
18507 return this.renderer.blockquote(body);
18509 case 'list_start': {
18511 , ordered = this.token.ordered;
18513 while (this.next().type !== 'list_end') {
18514 body += this.tok();
18517 return this.renderer.list(body, ordered);
18519 case 'list_item_start': {
18522 while (this.next().type !== 'list_item_end') {
18523 body += this.token.type === 'text'
18528 return this.renderer.listitem(body);
18530 case 'loose_item_start': {
18533 while (this.next().type !== 'list_item_end') {
18534 body += this.tok();
18537 return this.renderer.listitem(body);
18540 var html = !this.token.pre && !this.options.pedantic
18541 ? this.inline.output(this.token.text)
18543 return this.renderer.html(html);
18545 case 'paragraph': {
18546 return this.renderer.paragraph(this.inline.output(this.token.text));
18549 return this.renderer.paragraph(this.parseText());
18561 var marked = function (src, opt, callback) {
18562 if (callback || typeof opt === 'function') {
18568 opt = merge({}, marked.defaults, opt || {});
18570 var highlight = opt.highlight
18576 tokens = Lexer.lex(src, opt)
18578 return callback(e);
18581 pending = tokens.length;
18585 var done = function(err) {
18587 opt.highlight = highlight;
18588 return callback(err);
18594 out = Parser.parse(tokens, opt);
18599 opt.highlight = highlight;
18603 : callback(null, out);
18606 if (!highlight || highlight.length < 3) {
18610 delete opt.highlight;
18612 if (!pending) { return done(); }
18614 for (; i < tokens.length; i++) {
18616 if (token.type !== 'code') {
18617 return --pending || done();
18619 return highlight(token.text, token.lang, function(err, code) {
18620 if (err) { return done(err); }
18621 if (code == null || code === token.text) {
18622 return --pending || done();
18625 token.escaped = true;
18626 --pending || done();
18634 if (opt) { opt = merge({}, marked.defaults, opt); }
18635 return Parser.parse(Lexer.lex(src, opt), opt);
18637 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18638 if ((opt || marked.defaults).silent) {
18639 return '<p>An error occured:</p><pre>'
18640 + escape(e.message + '', true)
18652 marked.setOptions = function(opt) {
18653 merge(marked.defaults, opt);
18657 marked.defaults = {
18668 langPrefix: 'lang-',
18669 smartypants: false,
18671 renderer: new Renderer,
18679 marked.Parser = Parser;
18680 marked.parser = Parser.parse;
18682 marked.Renderer = Renderer;
18684 marked.Lexer = Lexer;
18685 marked.lexer = Lexer.lex;
18687 marked.InlineLexer = InlineLexer;
18688 marked.inlineLexer = InlineLexer.output;
18690 marked.parse = marked;
18692 Roo.Markdown.marked = marked;
18696 * Ext JS Library 1.1.1
18697 * Copyright(c) 2006-2007, Ext JS, LLC.
18699 * Originally Released Under LGPL - original licence link has changed is not relivant.
18702 * <script type="text/javascript">
18708 * These classes are derivatives of the similarly named classes in the YUI Library.
18709 * The original license:
18710 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18711 * Code licensed under the BSD License:
18712 * http://developer.yahoo.net/yui/license.txt
18717 var Event=Roo.EventManager;
18718 var Dom=Roo.lib.Dom;
18721 * @class Roo.dd.DragDrop
18722 * @extends Roo.util.Observable
18723 * Defines the interface and base operation of items that that can be
18724 * dragged or can be drop targets. It was designed to be extended, overriding
18725 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18726 * Up to three html elements can be associated with a DragDrop instance:
18728 * <li>linked element: the element that is passed into the constructor.
18729 * This is the element which defines the boundaries for interaction with
18730 * other DragDrop objects.</li>
18731 * <li>handle element(s): The drag operation only occurs if the element that
18732 * was clicked matches a handle element. By default this is the linked
18733 * element, but there are times that you will want only a portion of the
18734 * linked element to initiate the drag operation, and the setHandleElId()
18735 * method provides a way to define this.</li>
18736 * <li>drag element: this represents the element that would be moved along
18737 * with the cursor during a drag operation. By default, this is the linked
18738 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18739 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18742 * This class should not be instantiated until the onload event to ensure that
18743 * the associated elements are available.
18744 * The following would define a DragDrop obj that would interact with any
18745 * other DragDrop obj in the "group1" group:
18747 * dd = new Roo.dd.DragDrop("div1", "group1");
18749 * Since none of the event handlers have been implemented, nothing would
18750 * actually happen if you were to run the code above. Normally you would
18751 * override this class or one of the default implementations, but you can
18752 * also override the methods you want on an instance of the class...
18754 * dd.onDragDrop = function(e, id) {
18755 * alert("dd was dropped on " + id);
18759 * @param {String} id of the element that is linked to this instance
18760 * @param {String} sGroup the group of related DragDrop objects
18761 * @param {object} config an object containing configurable attributes
18762 * Valid properties for DragDrop:
18763 * padding, isTarget, maintainOffset, primaryButtonOnly
18765 Roo.dd.DragDrop = function(id, sGroup, config) {
18767 this.init(id, sGroup, config);
18772 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18775 * The id of the element associated with this object. This is what we
18776 * refer to as the "linked element" because the size and position of
18777 * this element is used to determine when the drag and drop objects have
18785 * Configuration attributes passed into the constructor
18792 * The id of the element that will be dragged. By default this is same
18793 * as the linked element , but could be changed to another element. Ex:
18795 * @property dragElId
18802 * the id of the element that initiates the drag operation. By default
18803 * this is the linked element, but could be changed to be a child of this
18804 * element. This lets us do things like only starting the drag when the
18805 * header element within the linked html element is clicked.
18806 * @property handleElId
18813 * An associative array of HTML tags that will be ignored if clicked.
18814 * @property invalidHandleTypes
18815 * @type {string: string}
18817 invalidHandleTypes: null,
18820 * An associative array of ids for elements that will be ignored if clicked
18821 * @property invalidHandleIds
18822 * @type {string: string}
18824 invalidHandleIds: null,
18827 * An indexted array of css class names for elements that will be ignored
18829 * @property invalidHandleClasses
18832 invalidHandleClasses: null,
18835 * The linked element's absolute X position at the time the drag was
18837 * @property startPageX
18844 * The linked element's absolute X position at the time the drag was
18846 * @property startPageY
18853 * The group defines a logical collection of DragDrop objects that are
18854 * related. Instances only get events when interacting with other
18855 * DragDrop object in the same group. This lets us define multiple
18856 * groups using a single DragDrop subclass if we want.
18858 * @type {string: string}
18863 * Individual drag/drop instances can be locked. This will prevent
18864 * onmousedown start drag.
18872 * Lock this instance
18875 lock: function() { this.locked = true; },
18878 * Unlock this instace
18881 unlock: function() { this.locked = false; },
18884 * By default, all insances can be a drop target. This can be disabled by
18885 * setting isTarget to false.
18892 * The padding configured for this drag and drop object for calculating
18893 * the drop zone intersection with this object.
18900 * Cached reference to the linked element
18901 * @property _domRef
18907 * Internal typeof flag
18908 * @property __ygDragDrop
18911 __ygDragDrop: true,
18914 * Set to true when horizontal contraints are applied
18915 * @property constrainX
18922 * Set to true when vertical contraints are applied
18923 * @property constrainY
18930 * The left constraint
18938 * The right constraint
18946 * The up constraint
18955 * The down constraint
18963 * Maintain offsets when we resetconstraints. Set to true when you want
18964 * the position of the element relative to its parent to stay the same
18965 * when the page changes
18967 * @property maintainOffset
18970 maintainOffset: false,
18973 * Array of pixel locations the element will snap to if we specified a
18974 * horizontal graduation/interval. This array is generated automatically
18975 * when you define a tick interval.
18982 * Array of pixel locations the element will snap to if we specified a
18983 * vertical graduation/interval. This array is generated automatically
18984 * when you define a tick interval.
18991 * By default the drag and drop instance will only respond to the primary
18992 * button click (left button for a right-handed mouse). Set to true to
18993 * allow drag and drop to start with any mouse click that is propogated
18995 * @property primaryButtonOnly
18998 primaryButtonOnly: true,
19001 * The availabe property is false until the linked dom element is accessible.
19002 * @property available
19008 * By default, drags can only be initiated if the mousedown occurs in the
19009 * region the linked element is. This is done in part to work around a
19010 * bug in some browsers that mis-report the mousedown if the previous
19011 * mouseup happened outside of the window. This property is set to true
19012 * if outer handles are defined.
19014 * @property hasOuterHandles
19018 hasOuterHandles: false,
19021 * Code that executes immediately before the startDrag event
19022 * @method b4StartDrag
19025 b4StartDrag: function(x, y) { },
19028 * Abstract method called after a drag/drop object is clicked
19029 * and the drag or mousedown time thresholds have beeen met.
19030 * @method startDrag
19031 * @param {int} X click location
19032 * @param {int} Y click location
19034 startDrag: function(x, y) { /* override this */ },
19037 * Code that executes immediately before the onDrag event
19041 b4Drag: function(e) { },
19044 * Abstract method called during the onMouseMove event while dragging an
19047 * @param {Event} e the mousemove event
19049 onDrag: function(e) { /* override this */ },
19052 * Abstract method called when this element fist begins hovering over
19053 * another DragDrop obj
19054 * @method onDragEnter
19055 * @param {Event} e the mousemove event
19056 * @param {String|DragDrop[]} id In POINT mode, the element
19057 * id this is hovering over. In INTERSECT mode, an array of one or more
19058 * dragdrop items being hovered over.
19060 onDragEnter: function(e, id) { /* override this */ },
19063 * Code that executes immediately before the onDragOver event
19064 * @method b4DragOver
19067 b4DragOver: function(e) { },
19070 * Abstract method called when this element is hovering over another
19072 * @method onDragOver
19073 * @param {Event} e the mousemove event
19074 * @param {String|DragDrop[]} id In POINT mode, the element
19075 * id this is hovering over. In INTERSECT mode, an array of dd items
19076 * being hovered over.
19078 onDragOver: function(e, id) { /* override this */ },
19081 * Code that executes immediately before the onDragOut event
19082 * @method b4DragOut
19085 b4DragOut: function(e) { },
19088 * Abstract method called when we are no longer hovering over an element
19089 * @method onDragOut
19090 * @param {Event} e the mousemove event
19091 * @param {String|DragDrop[]} id In POINT mode, the element
19092 * id this was hovering over. In INTERSECT mode, an array of dd items
19093 * that the mouse is no longer over.
19095 onDragOut: function(e, id) { /* override this */ },
19098 * Code that executes immediately before the onDragDrop event
19099 * @method b4DragDrop
19102 b4DragDrop: function(e) { },
19105 * Abstract method called when this item is dropped on another DragDrop
19107 * @method onDragDrop
19108 * @param {Event} e the mouseup event
19109 * @param {String|DragDrop[]} id In POINT mode, the element
19110 * id this was dropped on. In INTERSECT mode, an array of dd items this
19113 onDragDrop: function(e, id) { /* override this */ },
19116 * Abstract method called when this item is dropped on an area with no
19118 * @method onInvalidDrop
19119 * @param {Event} e the mouseup event
19121 onInvalidDrop: function(e) { /* override this */ },
19124 * Code that executes immediately before the endDrag event
19125 * @method b4EndDrag
19128 b4EndDrag: function(e) { },
19131 * Fired when we are done dragging the object
19133 * @param {Event} e the mouseup event
19135 endDrag: function(e) { /* override this */ },
19138 * Code executed immediately before the onMouseDown event
19139 * @method b4MouseDown
19140 * @param {Event} e the mousedown event
19143 b4MouseDown: function(e) { },
19146 * Event handler that fires when a drag/drop obj gets a mousedown
19147 * @method onMouseDown
19148 * @param {Event} e the mousedown event
19150 onMouseDown: function(e) { /* override this */ },
19153 * Event handler that fires when a drag/drop obj gets a mouseup
19154 * @method onMouseUp
19155 * @param {Event} e the mouseup event
19157 onMouseUp: function(e) { /* override this */ },
19160 * Override the onAvailable method to do what is needed after the initial
19161 * position was determined.
19162 * @method onAvailable
19164 onAvailable: function () {
19168 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19171 defaultPadding : {left:0, right:0, top:0, bottom:0},
19174 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19178 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19179 { dragElId: "existingProxyDiv" });
19180 dd.startDrag = function(){
19181 this.constrainTo("parent-id");
19184 * Or you can initalize it using the {@link Roo.Element} object:
19186 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19187 startDrag : function(){
19188 this.constrainTo("parent-id");
19192 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19193 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19194 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19195 * an object containing the sides to pad. For example: {right:10, bottom:10}
19196 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19198 constrainTo : function(constrainTo, pad, inContent){
19199 if(typeof pad == "number"){
19200 pad = {left: pad, right:pad, top:pad, bottom:pad};
19202 pad = pad || this.defaultPadding;
19203 var b = Roo.get(this.getEl()).getBox();
19204 var ce = Roo.get(constrainTo);
19205 var s = ce.getScroll();
19206 var c, cd = ce.dom;
19207 if(cd == document.body){
19208 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19211 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19215 var topSpace = b.y - c.y;
19216 var leftSpace = b.x - c.x;
19218 this.resetConstraints();
19219 this.setXConstraint(leftSpace - (pad.left||0), // left
19220 c.width - leftSpace - b.width - (pad.right||0) //right
19222 this.setYConstraint(topSpace - (pad.top||0), //top
19223 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19228 * Returns a reference to the linked element
19230 * @return {HTMLElement} the html element
19232 getEl: function() {
19233 if (!this._domRef) {
19234 this._domRef = Roo.getDom(this.id);
19237 return this._domRef;
19241 * Returns a reference to the actual element to drag. By default this is
19242 * the same as the html element, but it can be assigned to another
19243 * element. An example of this can be found in Roo.dd.DDProxy
19244 * @method getDragEl
19245 * @return {HTMLElement} the html element
19247 getDragEl: function() {
19248 return Roo.getDom(this.dragElId);
19252 * Sets up the DragDrop object. Must be called in the constructor of any
19253 * Roo.dd.DragDrop subclass
19255 * @param id the id of the linked element
19256 * @param {String} sGroup the group of related items
19257 * @param {object} config configuration attributes
19259 init: function(id, sGroup, config) {
19260 this.initTarget(id, sGroup, config);
19261 if (!Roo.isTouch) {
19262 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19264 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19265 // Event.on(this.id, "selectstart", Event.preventDefault);
19269 * Initializes Targeting functionality only... the object does not
19270 * get a mousedown handler.
19271 * @method initTarget
19272 * @param id the id of the linked element
19273 * @param {String} sGroup the group of related items
19274 * @param {object} config configuration attributes
19276 initTarget: function(id, sGroup, config) {
19278 // configuration attributes
19279 this.config = config || {};
19281 // create a local reference to the drag and drop manager
19282 this.DDM = Roo.dd.DDM;
19283 // initialize the groups array
19286 // assume that we have an element reference instead of an id if the
19287 // parameter is not a string
19288 if (typeof id !== "string") {
19295 // add to an interaction group
19296 this.addToGroup((sGroup) ? sGroup : "default");
19298 // We don't want to register this as the handle with the manager
19299 // so we just set the id rather than calling the setter.
19300 this.handleElId = id;
19302 // the linked element is the element that gets dragged by default
19303 this.setDragElId(id);
19305 // by default, clicked anchors will not start drag operations.
19306 this.invalidHandleTypes = { A: "A" };
19307 this.invalidHandleIds = {};
19308 this.invalidHandleClasses = [];
19310 this.applyConfig();
19312 this.handleOnAvailable();
19316 * Applies the configuration parameters that were passed into the constructor.
19317 * This is supposed to happen at each level through the inheritance chain. So
19318 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19319 * DragDrop in order to get all of the parameters that are available in
19321 * @method applyConfig
19323 applyConfig: function() {
19325 // configurable properties:
19326 // padding, isTarget, maintainOffset, primaryButtonOnly
19327 this.padding = this.config.padding || [0, 0, 0, 0];
19328 this.isTarget = (this.config.isTarget !== false);
19329 this.maintainOffset = (this.config.maintainOffset);
19330 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19335 * Executed when the linked element is available
19336 * @method handleOnAvailable
19339 handleOnAvailable: function() {
19340 this.available = true;
19341 this.resetConstraints();
19342 this.onAvailable();
19346 * Configures the padding for the target zone in px. Effectively expands
19347 * (or reduces) the virtual object size for targeting calculations.
19348 * Supports css-style shorthand; if only one parameter is passed, all sides
19349 * will have that padding, and if only two are passed, the top and bottom
19350 * will have the first param, the left and right the second.
19351 * @method setPadding
19352 * @param {int} iTop Top pad
19353 * @param {int} iRight Right pad
19354 * @param {int} iBot Bot pad
19355 * @param {int} iLeft Left pad
19357 setPadding: function(iTop, iRight, iBot, iLeft) {
19358 // this.padding = [iLeft, iRight, iTop, iBot];
19359 if (!iRight && 0 !== iRight) {
19360 this.padding = [iTop, iTop, iTop, iTop];
19361 } else if (!iBot && 0 !== iBot) {
19362 this.padding = [iTop, iRight, iTop, iRight];
19364 this.padding = [iTop, iRight, iBot, iLeft];
19369 * Stores the initial placement of the linked element.
19370 * @method setInitialPosition
19371 * @param {int} diffX the X offset, default 0
19372 * @param {int} diffY the Y offset, default 0
19374 setInitPosition: function(diffX, diffY) {
19375 var el = this.getEl();
19377 if (!this.DDM.verifyEl(el)) {
19381 var dx = diffX || 0;
19382 var dy = diffY || 0;
19384 var p = Dom.getXY( el );
19386 this.initPageX = p[0] - dx;
19387 this.initPageY = p[1] - dy;
19389 this.lastPageX = p[0];
19390 this.lastPageY = p[1];
19393 this.setStartPosition(p);
19397 * Sets the start position of the element. This is set when the obj
19398 * is initialized, the reset when a drag is started.
19399 * @method setStartPosition
19400 * @param pos current position (from previous lookup)
19403 setStartPosition: function(pos) {
19404 var p = pos || Dom.getXY( this.getEl() );
19405 this.deltaSetXY = null;
19407 this.startPageX = p[0];
19408 this.startPageY = p[1];
19412 * Add this instance to a group of related drag/drop objects. All
19413 * instances belong to at least one group, and can belong to as many
19414 * groups as needed.
19415 * @method addToGroup
19416 * @param sGroup {string} the name of the group
19418 addToGroup: function(sGroup) {
19419 this.groups[sGroup] = true;
19420 this.DDM.regDragDrop(this, sGroup);
19424 * Remove's this instance from the supplied interaction group
19425 * @method removeFromGroup
19426 * @param {string} sGroup The group to drop
19428 removeFromGroup: function(sGroup) {
19429 if (this.groups[sGroup]) {
19430 delete this.groups[sGroup];
19433 this.DDM.removeDDFromGroup(this, sGroup);
19437 * Allows you to specify that an element other than the linked element
19438 * will be moved with the cursor during a drag
19439 * @method setDragElId
19440 * @param id {string} the id of the element that will be used to initiate the drag
19442 setDragElId: function(id) {
19443 this.dragElId = id;
19447 * Allows you to specify a child of the linked element that should be
19448 * used to initiate the drag operation. An example of this would be if
19449 * you have a content div with text and links. Clicking anywhere in the
19450 * content area would normally start the drag operation. Use this method
19451 * to specify that an element inside of the content div is the element
19452 * that starts the drag operation.
19453 * @method setHandleElId
19454 * @param id {string} the id of the element that will be used to
19455 * initiate the drag.
19457 setHandleElId: function(id) {
19458 if (typeof id !== "string") {
19461 this.handleElId = id;
19462 this.DDM.regHandle(this.id, id);
19466 * Allows you to set an element outside of the linked element as a drag
19468 * @method setOuterHandleElId
19469 * @param id the id of the element that will be used to initiate the drag
19471 setOuterHandleElId: function(id) {
19472 if (typeof id !== "string") {
19475 Event.on(id, "mousedown",
19476 this.handleMouseDown, this);
19477 this.setHandleElId(id);
19479 this.hasOuterHandles = true;
19483 * Remove all drag and drop hooks for this element
19486 unreg: function() {
19487 Event.un(this.id, "mousedown",
19488 this.handleMouseDown);
19489 Event.un(this.id, "touchstart",
19490 this.handleMouseDown);
19491 this._domRef = null;
19492 this.DDM._remove(this);
19495 destroy : function(){
19500 * Returns true if this instance is locked, or the drag drop mgr is locked
19501 * (meaning that all drag/drop is disabled on the page.)
19503 * @return {boolean} true if this obj or all drag/drop is locked, else
19506 isLocked: function() {
19507 return (this.DDM.isLocked() || this.locked);
19511 * Fired when this object is clicked
19512 * @method handleMouseDown
19514 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19517 handleMouseDown: function(e, oDD){
19519 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19520 //Roo.log('not touch/ button !=0');
19523 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19524 return; // double touch..
19528 if (this.isLocked()) {
19529 //Roo.log('locked');
19533 this.DDM.refreshCache(this.groups);
19534 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19535 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19536 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19537 //Roo.log('no outer handes or not over target');
19540 // Roo.log('check validator');
19541 if (this.clickValidator(e)) {
19542 // Roo.log('validate success');
19543 // set the initial element position
19544 this.setStartPosition();
19547 this.b4MouseDown(e);
19548 this.onMouseDown(e);
19550 this.DDM.handleMouseDown(e, this);
19552 this.DDM.stopEvent(e);
19560 clickValidator: function(e) {
19561 var target = e.getTarget();
19562 return ( this.isValidHandleChild(target) &&
19563 (this.id == this.handleElId ||
19564 this.DDM.handleWasClicked(target, this.id)) );
19568 * Allows you to specify a tag name that should not start a drag operation
19569 * when clicked. This is designed to facilitate embedding links within a
19570 * drag handle that do something other than start the drag.
19571 * @method addInvalidHandleType
19572 * @param {string} tagName the type of element to exclude
19574 addInvalidHandleType: function(tagName) {
19575 var type = tagName.toUpperCase();
19576 this.invalidHandleTypes[type] = type;
19580 * Lets you to specify an element id for a child of a drag handle
19581 * that should not initiate a drag
19582 * @method addInvalidHandleId
19583 * @param {string} id the element id of the element you wish to ignore
19585 addInvalidHandleId: function(id) {
19586 if (typeof id !== "string") {
19589 this.invalidHandleIds[id] = id;
19593 * Lets you specify a css class of elements that will not initiate a drag
19594 * @method addInvalidHandleClass
19595 * @param {string} cssClass the class of the elements you wish to ignore
19597 addInvalidHandleClass: function(cssClass) {
19598 this.invalidHandleClasses.push(cssClass);
19602 * Unsets an excluded tag name set by addInvalidHandleType
19603 * @method removeInvalidHandleType
19604 * @param {string} tagName the type of element to unexclude
19606 removeInvalidHandleType: function(tagName) {
19607 var type = tagName.toUpperCase();
19608 // this.invalidHandleTypes[type] = null;
19609 delete this.invalidHandleTypes[type];
19613 * Unsets an invalid handle id
19614 * @method removeInvalidHandleId
19615 * @param {string} id the id of the element to re-enable
19617 removeInvalidHandleId: function(id) {
19618 if (typeof id !== "string") {
19621 delete this.invalidHandleIds[id];
19625 * Unsets an invalid css class
19626 * @method removeInvalidHandleClass
19627 * @param {string} cssClass the class of the element(s) you wish to
19630 removeInvalidHandleClass: function(cssClass) {
19631 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19632 if (this.invalidHandleClasses[i] == cssClass) {
19633 delete this.invalidHandleClasses[i];
19639 * Checks the tag exclusion list to see if this click should be ignored
19640 * @method isValidHandleChild
19641 * @param {HTMLElement} node the HTMLElement to evaluate
19642 * @return {boolean} true if this is a valid tag type, false if not
19644 isValidHandleChild: function(node) {
19647 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19650 nodeName = node.nodeName.toUpperCase();
19652 nodeName = node.nodeName;
19654 valid = valid && !this.invalidHandleTypes[nodeName];
19655 valid = valid && !this.invalidHandleIds[node.id];
19657 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19658 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19667 * Create the array of horizontal tick marks if an interval was specified
19668 * in setXConstraint().
19669 * @method setXTicks
19672 setXTicks: function(iStartX, iTickSize) {
19674 this.xTickSize = iTickSize;
19678 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19680 this.xTicks[this.xTicks.length] = i;
19685 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19687 this.xTicks[this.xTicks.length] = i;
19692 this.xTicks.sort(this.DDM.numericSort) ;
19696 * Create the array of vertical tick marks if an interval was specified in
19697 * setYConstraint().
19698 * @method setYTicks
19701 setYTicks: function(iStartY, iTickSize) {
19703 this.yTickSize = iTickSize;
19707 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19709 this.yTicks[this.yTicks.length] = i;
19714 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19716 this.yTicks[this.yTicks.length] = i;
19721 this.yTicks.sort(this.DDM.numericSort) ;
19725 * By default, the element can be dragged any place on the screen. Use
19726 * this method to limit the horizontal travel of the element. Pass in
19727 * 0,0 for the parameters if you want to lock the drag to the y axis.
19728 * @method setXConstraint
19729 * @param {int} iLeft the number of pixels the element can move to the left
19730 * @param {int} iRight the number of pixels the element can move to the
19732 * @param {int} iTickSize optional parameter for specifying that the
19734 * should move iTickSize pixels at a time.
19736 setXConstraint: function(iLeft, iRight, iTickSize) {
19737 this.leftConstraint = iLeft;
19738 this.rightConstraint = iRight;
19740 this.minX = this.initPageX - iLeft;
19741 this.maxX = this.initPageX + iRight;
19742 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19744 this.constrainX = true;
19748 * Clears any constraints applied to this instance. Also clears ticks
19749 * since they can't exist independent of a constraint at this time.
19750 * @method clearConstraints
19752 clearConstraints: function() {
19753 this.constrainX = false;
19754 this.constrainY = false;
19759 * Clears any tick interval defined for this instance
19760 * @method clearTicks
19762 clearTicks: function() {
19763 this.xTicks = null;
19764 this.yTicks = null;
19765 this.xTickSize = 0;
19766 this.yTickSize = 0;
19770 * By default, the element can be dragged any place on the screen. Set
19771 * this to limit the vertical travel of the element. Pass in 0,0 for the
19772 * parameters if you want to lock the drag to the x axis.
19773 * @method setYConstraint
19774 * @param {int} iUp the number of pixels the element can move up
19775 * @param {int} iDown the number of pixels the element can move down
19776 * @param {int} iTickSize optional parameter for specifying that the
19777 * element should move iTickSize pixels at a time.
19779 setYConstraint: function(iUp, iDown, iTickSize) {
19780 this.topConstraint = iUp;
19781 this.bottomConstraint = iDown;
19783 this.minY = this.initPageY - iUp;
19784 this.maxY = this.initPageY + iDown;
19785 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19787 this.constrainY = true;
19792 * resetConstraints must be called if you manually reposition a dd element.
19793 * @method resetConstraints
19794 * @param {boolean} maintainOffset
19796 resetConstraints: function() {
19799 // Maintain offsets if necessary
19800 if (this.initPageX || this.initPageX === 0) {
19801 // figure out how much this thing has moved
19802 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19803 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19805 this.setInitPosition(dx, dy);
19807 // This is the first time we have detected the element's position
19809 this.setInitPosition();
19812 if (this.constrainX) {
19813 this.setXConstraint( this.leftConstraint,
19814 this.rightConstraint,
19818 if (this.constrainY) {
19819 this.setYConstraint( this.topConstraint,
19820 this.bottomConstraint,
19826 * Normally the drag element is moved pixel by pixel, but we can specify
19827 * that it move a number of pixels at a time. This method resolves the
19828 * location when we have it set up like this.
19830 * @param {int} val where we want to place the object
19831 * @param {int[]} tickArray sorted array of valid points
19832 * @return {int} the closest tick
19835 getTick: function(val, tickArray) {
19838 // If tick interval is not defined, it is effectively 1 pixel,
19839 // so we return the value passed to us.
19841 } else if (tickArray[0] >= val) {
19842 // The value is lower than the first tick, so we return the first
19844 return tickArray[0];
19846 for (var i=0, len=tickArray.length; i<len; ++i) {
19848 if (tickArray[next] && tickArray[next] >= val) {
19849 var diff1 = val - tickArray[i];
19850 var diff2 = tickArray[next] - val;
19851 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19855 // The value is larger than the last tick, so we return the last
19857 return tickArray[tickArray.length - 1];
19864 * @return {string} string representation of the dd obj
19866 toString: function() {
19867 return ("DragDrop " + this.id);
19875 * Ext JS Library 1.1.1
19876 * Copyright(c) 2006-2007, Ext JS, LLC.
19878 * Originally Released Under LGPL - original licence link has changed is not relivant.
19881 * <script type="text/javascript">
19886 * The drag and drop utility provides a framework for building drag and drop
19887 * applications. In addition to enabling drag and drop for specific elements,
19888 * the drag and drop elements are tracked by the manager class, and the
19889 * interactions between the various elements are tracked during the drag and
19890 * the implementing code is notified about these important moments.
19893 // Only load the library once. Rewriting the manager class would orphan
19894 // existing drag and drop instances.
19895 if (!Roo.dd.DragDropMgr) {
19898 * @class Roo.dd.DragDropMgr
19899 * DragDropMgr is a singleton that tracks the element interaction for
19900 * all DragDrop items in the window. Generally, you will not call
19901 * this class directly, but it does have helper methods that could
19902 * be useful in your DragDrop implementations.
19905 Roo.dd.DragDropMgr = function() {
19907 var Event = Roo.EventManager;
19912 * Two dimensional Array of registered DragDrop objects. The first
19913 * dimension is the DragDrop item group, the second the DragDrop
19916 * @type {string: string}
19923 * Array of element ids defined as drag handles. Used to determine
19924 * if the element that generated the mousedown event is actually the
19925 * handle and not the html element itself.
19926 * @property handleIds
19927 * @type {string: string}
19934 * the DragDrop object that is currently being dragged
19935 * @property dragCurrent
19943 * the DragDrop object(s) that are being hovered over
19944 * @property dragOvers
19952 * the X distance between the cursor and the object being dragged
19961 * the Y distance between the cursor and the object being dragged
19970 * Flag to determine if we should prevent the default behavior of the
19971 * events we define. By default this is true, but this can be set to
19972 * false if you need the default behavior (not recommended)
19973 * @property preventDefault
19977 preventDefault: true,
19980 * Flag to determine if we should stop the propagation of the events
19981 * we generate. This is true by default but you may want to set it to
19982 * false if the html element contains other features that require the
19984 * @property stopPropagation
19988 stopPropagation: true,
19991 * Internal flag that is set to true when drag and drop has been
19993 * @property initialized
20000 * All drag and drop can be disabled.
20008 * Called the first time an element is registered.
20014 this.initialized = true;
20018 * In point mode, drag and drop interaction is defined by the
20019 * location of the cursor during the drag/drop
20027 * In intersect mode, drag and drop interactio nis defined by the
20028 * overlap of two or more drag and drop objects.
20029 * @property INTERSECT
20036 * The current drag and drop mode. Default: POINT
20044 * Runs method on all drag and drop objects
20045 * @method _execOnAll
20049 _execOnAll: function(sMethod, args) {
20050 for (var i in this.ids) {
20051 for (var j in this.ids[i]) {
20052 var oDD = this.ids[i][j];
20053 if (! this.isTypeOfDD(oDD)) {
20056 oDD[sMethod].apply(oDD, args);
20062 * Drag and drop initialization. Sets up the global event handlers
20067 _onLoad: function() {
20071 if (!Roo.isTouch) {
20072 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20073 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20075 Event.on(document, "touchend", this.handleMouseUp, this, true);
20076 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20078 Event.on(window, "unload", this._onUnload, this, true);
20079 Event.on(window, "resize", this._onResize, this, true);
20080 // Event.on(window, "mouseout", this._test);
20085 * Reset constraints on all drag and drop objs
20086 * @method _onResize
20090 _onResize: function(e) {
20091 this._execOnAll("resetConstraints", []);
20095 * Lock all drag and drop functionality
20099 lock: function() { this.locked = true; },
20102 * Unlock all drag and drop functionality
20106 unlock: function() { this.locked = false; },
20109 * Is drag and drop locked?
20111 * @return {boolean} True if drag and drop is locked, false otherwise.
20114 isLocked: function() { return this.locked; },
20117 * Location cache that is set for all drag drop objects when a drag is
20118 * initiated, cleared when the drag is finished.
20119 * @property locationCache
20126 * Set useCache to false if you want to force object the lookup of each
20127 * drag and drop linked element constantly during a drag.
20128 * @property useCache
20135 * The number of pixels that the mouse needs to move after the
20136 * mousedown before the drag is initiated. Default=3;
20137 * @property clickPixelThresh
20141 clickPixelThresh: 3,
20144 * The number of milliseconds after the mousedown event to initiate the
20145 * drag if we don't get a mouseup event. Default=1000
20146 * @property clickTimeThresh
20150 clickTimeThresh: 350,
20153 * Flag that indicates that either the drag pixel threshold or the
20154 * mousdown time threshold has been met
20155 * @property dragThreshMet
20160 dragThreshMet: false,
20163 * Timeout used for the click time threshold
20164 * @property clickTimeout
20169 clickTimeout: null,
20172 * The X position of the mousedown event stored for later use when a
20173 * drag threshold is met.
20182 * The Y position of the mousedown event stored for later use when a
20183 * drag threshold is met.
20192 * Each DragDrop instance must be registered with the DragDropMgr.
20193 * This is executed in DragDrop.init()
20194 * @method regDragDrop
20195 * @param {DragDrop} oDD the DragDrop object to register
20196 * @param {String} sGroup the name of the group this element belongs to
20199 regDragDrop: function(oDD, sGroup) {
20200 if (!this.initialized) { this.init(); }
20202 if (!this.ids[sGroup]) {
20203 this.ids[sGroup] = {};
20205 this.ids[sGroup][oDD.id] = oDD;
20209 * Removes the supplied dd instance from the supplied group. Executed
20210 * by DragDrop.removeFromGroup, so don't call this function directly.
20211 * @method removeDDFromGroup
20215 removeDDFromGroup: function(oDD, sGroup) {
20216 if (!this.ids[sGroup]) {
20217 this.ids[sGroup] = {};
20220 var obj = this.ids[sGroup];
20221 if (obj && obj[oDD.id]) {
20222 delete obj[oDD.id];
20227 * Unregisters a drag and drop item. This is executed in
20228 * DragDrop.unreg, use that method instead of calling this directly.
20233 _remove: function(oDD) {
20234 for (var g in oDD.groups) {
20235 if (g && this.ids[g][oDD.id]) {
20236 delete this.ids[g][oDD.id];
20239 delete this.handleIds[oDD.id];
20243 * Each DragDrop handle element must be registered. This is done
20244 * automatically when executing DragDrop.setHandleElId()
20245 * @method regHandle
20246 * @param {String} sDDId the DragDrop id this element is a handle for
20247 * @param {String} sHandleId the id of the element that is the drag
20251 regHandle: function(sDDId, sHandleId) {
20252 if (!this.handleIds[sDDId]) {
20253 this.handleIds[sDDId] = {};
20255 this.handleIds[sDDId][sHandleId] = sHandleId;
20259 * Utility function to determine if a given element has been
20260 * registered as a drag drop item.
20261 * @method isDragDrop
20262 * @param {String} id the element id to check
20263 * @return {boolean} true if this element is a DragDrop item,
20267 isDragDrop: function(id) {
20268 return ( this.getDDById(id) ) ? true : false;
20272 * Returns the drag and drop instances that are in all groups the
20273 * passed in instance belongs to.
20274 * @method getRelated
20275 * @param {DragDrop} p_oDD the obj to get related data for
20276 * @param {boolean} bTargetsOnly if true, only return targetable objs
20277 * @return {DragDrop[]} the related instances
20280 getRelated: function(p_oDD, bTargetsOnly) {
20282 for (var i in p_oDD.groups) {
20283 for (j in this.ids[i]) {
20284 var dd = this.ids[i][j];
20285 if (! this.isTypeOfDD(dd)) {
20288 if (!bTargetsOnly || dd.isTarget) {
20289 oDDs[oDDs.length] = dd;
20298 * Returns true if the specified dd target is a legal target for
20299 * the specifice drag obj
20300 * @method isLegalTarget
20301 * @param {DragDrop} the drag obj
20302 * @param {DragDrop} the target
20303 * @return {boolean} true if the target is a legal target for the
20307 isLegalTarget: function (oDD, oTargetDD) {
20308 var targets = this.getRelated(oDD, true);
20309 for (var i=0, len=targets.length;i<len;++i) {
20310 if (targets[i].id == oTargetDD.id) {
20319 * My goal is to be able to transparently determine if an object is
20320 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20321 * returns "object", oDD.constructor.toString() always returns
20322 * "DragDrop" and not the name of the subclass. So for now it just
20323 * evaluates a well-known variable in DragDrop.
20324 * @method isTypeOfDD
20325 * @param {Object} the object to evaluate
20326 * @return {boolean} true if typeof oDD = DragDrop
20329 isTypeOfDD: function (oDD) {
20330 return (oDD && oDD.__ygDragDrop);
20334 * Utility function to determine if a given element has been
20335 * registered as a drag drop handle for the given Drag Drop object.
20337 * @param {String} id the element id to check
20338 * @return {boolean} true if this element is a DragDrop handle, false
20342 isHandle: function(sDDId, sHandleId) {
20343 return ( this.handleIds[sDDId] &&
20344 this.handleIds[sDDId][sHandleId] );
20348 * Returns the DragDrop instance for a given id
20349 * @method getDDById
20350 * @param {String} id the id of the DragDrop object
20351 * @return {DragDrop} the drag drop object, null if it is not found
20354 getDDById: function(id) {
20355 for (var i in this.ids) {
20356 if (this.ids[i][id]) {
20357 return this.ids[i][id];
20364 * Fired after a registered DragDrop object gets the mousedown event.
20365 * Sets up the events required to track the object being dragged
20366 * @method handleMouseDown
20367 * @param {Event} e the event
20368 * @param oDD the DragDrop object being dragged
20372 handleMouseDown: function(e, oDD) {
20374 Roo.QuickTips.disable();
20376 this.currentTarget = e.getTarget();
20378 this.dragCurrent = oDD;
20380 var el = oDD.getEl();
20382 // track start position
20383 this.startX = e.getPageX();
20384 this.startY = e.getPageY();
20386 this.deltaX = this.startX - el.offsetLeft;
20387 this.deltaY = this.startY - el.offsetTop;
20389 this.dragThreshMet = false;
20391 this.clickTimeout = setTimeout(
20393 var DDM = Roo.dd.DDM;
20394 DDM.startDrag(DDM.startX, DDM.startY);
20396 this.clickTimeThresh );
20400 * Fired when either the drag pixel threshol or the mousedown hold
20401 * time threshold has been met.
20402 * @method startDrag
20403 * @param x {int} the X position of the original mousedown
20404 * @param y {int} the Y position of the original mousedown
20407 startDrag: function(x, y) {
20408 clearTimeout(this.clickTimeout);
20409 if (this.dragCurrent) {
20410 this.dragCurrent.b4StartDrag(x, y);
20411 this.dragCurrent.startDrag(x, y);
20413 this.dragThreshMet = true;
20417 * Internal function to handle the mouseup event. Will be invoked
20418 * from the context of the document.
20419 * @method handleMouseUp
20420 * @param {Event} e the event
20424 handleMouseUp: function(e) {
20427 Roo.QuickTips.enable();
20429 if (! this.dragCurrent) {
20433 clearTimeout(this.clickTimeout);
20435 if (this.dragThreshMet) {
20436 this.fireEvents(e, true);
20446 * Utility to stop event propagation and event default, if these
20447 * features are turned on.
20448 * @method stopEvent
20449 * @param {Event} e the event as returned by this.getEvent()
20452 stopEvent: function(e){
20453 if(this.stopPropagation) {
20454 e.stopPropagation();
20457 if (this.preventDefault) {
20458 e.preventDefault();
20463 * Internal function to clean up event handlers after the drag
20464 * operation is complete
20466 * @param {Event} e the event
20470 stopDrag: function(e) {
20471 // Fire the drag end event for the item that was dragged
20472 if (this.dragCurrent) {
20473 if (this.dragThreshMet) {
20474 this.dragCurrent.b4EndDrag(e);
20475 this.dragCurrent.endDrag(e);
20478 this.dragCurrent.onMouseUp(e);
20481 this.dragCurrent = null;
20482 this.dragOvers = {};
20486 * Internal function to handle the mousemove event. Will be invoked
20487 * from the context of the html element.
20489 * @TODO figure out what we can do about mouse events lost when the
20490 * user drags objects beyond the window boundary. Currently we can
20491 * detect this in internet explorer by verifying that the mouse is
20492 * down during the mousemove event. Firefox doesn't give us the
20493 * button state on the mousemove event.
20494 * @method handleMouseMove
20495 * @param {Event} e the event
20499 handleMouseMove: function(e) {
20500 if (! this.dragCurrent) {
20504 // var button = e.which || e.button;
20506 // check for IE mouseup outside of page boundary
20507 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20509 return this.handleMouseUp(e);
20512 if (!this.dragThreshMet) {
20513 var diffX = Math.abs(this.startX - e.getPageX());
20514 var diffY = Math.abs(this.startY - e.getPageY());
20515 if (diffX > this.clickPixelThresh ||
20516 diffY > this.clickPixelThresh) {
20517 this.startDrag(this.startX, this.startY);
20521 if (this.dragThreshMet) {
20522 this.dragCurrent.b4Drag(e);
20523 this.dragCurrent.onDrag(e);
20524 if(!this.dragCurrent.moveOnly){
20525 this.fireEvents(e, false);
20535 * Iterates over all of the DragDrop elements to find ones we are
20536 * hovering over or dropping on
20537 * @method fireEvents
20538 * @param {Event} e the event
20539 * @param {boolean} isDrop is this a drop op or a mouseover op?
20543 fireEvents: function(e, isDrop) {
20544 var dc = this.dragCurrent;
20546 // If the user did the mouse up outside of the window, we could
20547 // get here even though we have ended the drag.
20548 if (!dc || dc.isLocked()) {
20552 var pt = e.getPoint();
20554 // cache the previous dragOver array
20560 var enterEvts = [];
20562 // Check to see if the object(s) we were hovering over is no longer
20563 // being hovered over so we can fire the onDragOut event
20564 for (var i in this.dragOvers) {
20566 var ddo = this.dragOvers[i];
20568 if (! this.isTypeOfDD(ddo)) {
20572 if (! this.isOverTarget(pt, ddo, this.mode)) {
20573 outEvts.push( ddo );
20576 oldOvers[i] = true;
20577 delete this.dragOvers[i];
20580 for (var sGroup in dc.groups) {
20582 if ("string" != typeof sGroup) {
20586 for (i in this.ids[sGroup]) {
20587 var oDD = this.ids[sGroup][i];
20588 if (! this.isTypeOfDD(oDD)) {
20592 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20593 if (this.isOverTarget(pt, oDD, this.mode)) {
20594 // look for drop interactions
20596 dropEvts.push( oDD );
20597 // look for drag enter and drag over interactions
20600 // initial drag over: dragEnter fires
20601 if (!oldOvers[oDD.id]) {
20602 enterEvts.push( oDD );
20603 // subsequent drag overs: dragOver fires
20605 overEvts.push( oDD );
20608 this.dragOvers[oDD.id] = oDD;
20616 if (outEvts.length) {
20617 dc.b4DragOut(e, outEvts);
20618 dc.onDragOut(e, outEvts);
20621 if (enterEvts.length) {
20622 dc.onDragEnter(e, enterEvts);
20625 if (overEvts.length) {
20626 dc.b4DragOver(e, overEvts);
20627 dc.onDragOver(e, overEvts);
20630 if (dropEvts.length) {
20631 dc.b4DragDrop(e, dropEvts);
20632 dc.onDragDrop(e, dropEvts);
20636 // fire dragout events
20638 for (i=0, len=outEvts.length; i<len; ++i) {
20639 dc.b4DragOut(e, outEvts[i].id);
20640 dc.onDragOut(e, outEvts[i].id);
20643 // fire enter events
20644 for (i=0,len=enterEvts.length; i<len; ++i) {
20645 // dc.b4DragEnter(e, oDD.id);
20646 dc.onDragEnter(e, enterEvts[i].id);
20649 // fire over events
20650 for (i=0,len=overEvts.length; i<len; ++i) {
20651 dc.b4DragOver(e, overEvts[i].id);
20652 dc.onDragOver(e, overEvts[i].id);
20655 // fire drop events
20656 for (i=0, len=dropEvts.length; i<len; ++i) {
20657 dc.b4DragDrop(e, dropEvts[i].id);
20658 dc.onDragDrop(e, dropEvts[i].id);
20663 // notify about a drop that did not find a target
20664 if (isDrop && !dropEvts.length) {
20665 dc.onInvalidDrop(e);
20671 * Helper function for getting the best match from the list of drag
20672 * and drop objects returned by the drag and drop events when we are
20673 * in INTERSECT mode. It returns either the first object that the
20674 * cursor is over, or the object that has the greatest overlap with
20675 * the dragged element.
20676 * @method getBestMatch
20677 * @param {DragDrop[]} dds The array of drag and drop objects
20679 * @return {DragDrop} The best single match
20682 getBestMatch: function(dds) {
20684 // Return null if the input is not what we expect
20685 //if (!dds || !dds.length || dds.length == 0) {
20687 // If there is only one item, it wins
20688 //} else if (dds.length == 1) {
20690 var len = dds.length;
20695 // Loop through the targeted items
20696 for (var i=0; i<len; ++i) {
20698 // If the cursor is over the object, it wins. If the
20699 // cursor is over multiple matches, the first one we come
20701 if (dd.cursorIsOver) {
20704 // Otherwise the object with the most overlap wins
20707 winner.overlap.getArea() < dd.overlap.getArea()) {
20718 * Refreshes the cache of the top-left and bottom-right points of the
20719 * drag and drop objects in the specified group(s). This is in the
20720 * format that is stored in the drag and drop instance, so typical
20723 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20727 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20729 * @TODO this really should be an indexed array. Alternatively this
20730 * method could accept both.
20731 * @method refreshCache
20732 * @param {Object} groups an associative array of groups to refresh
20735 refreshCache: function(groups) {
20736 for (var sGroup in groups) {
20737 if ("string" != typeof sGroup) {
20740 for (var i in this.ids[sGroup]) {
20741 var oDD = this.ids[sGroup][i];
20743 if (this.isTypeOfDD(oDD)) {
20744 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20745 var loc = this.getLocation(oDD);
20747 this.locationCache[oDD.id] = loc;
20749 delete this.locationCache[oDD.id];
20750 // this will unregister the drag and drop object if
20751 // the element is not in a usable state
20760 * This checks to make sure an element exists and is in the DOM. The
20761 * main purpose is to handle cases where innerHTML is used to remove
20762 * drag and drop objects from the DOM. IE provides an 'unspecified
20763 * error' when trying to access the offsetParent of such an element
20765 * @param {HTMLElement} el the element to check
20766 * @return {boolean} true if the element looks usable
20769 verifyEl: function(el) {
20774 parent = el.offsetParent;
20777 parent = el.offsetParent;
20788 * Returns a Region object containing the drag and drop element's position
20789 * and size, including the padding configured for it
20790 * @method getLocation
20791 * @param {DragDrop} oDD the drag and drop object to get the
20793 * @return {Roo.lib.Region} a Region object representing the total area
20794 * the element occupies, including any padding
20795 * the instance is configured for.
20798 getLocation: function(oDD) {
20799 if (! this.isTypeOfDD(oDD)) {
20803 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20806 pos= Roo.lib.Dom.getXY(el);
20814 x2 = x1 + el.offsetWidth;
20816 y2 = y1 + el.offsetHeight;
20818 t = y1 - oDD.padding[0];
20819 r = x2 + oDD.padding[1];
20820 b = y2 + oDD.padding[2];
20821 l = x1 - oDD.padding[3];
20823 return new Roo.lib.Region( t, r, b, l );
20827 * Checks the cursor location to see if it over the target
20828 * @method isOverTarget
20829 * @param {Roo.lib.Point} pt The point to evaluate
20830 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20831 * @return {boolean} true if the mouse is over the target
20835 isOverTarget: function(pt, oTarget, intersect) {
20836 // use cache if available
20837 var loc = this.locationCache[oTarget.id];
20838 if (!loc || !this.useCache) {
20839 loc = this.getLocation(oTarget);
20840 this.locationCache[oTarget.id] = loc;
20848 oTarget.cursorIsOver = loc.contains( pt );
20850 // DragDrop is using this as a sanity check for the initial mousedown
20851 // in this case we are done. In POINT mode, if the drag obj has no
20852 // contraints, we are also done. Otherwise we need to evaluate the
20853 // location of the target as related to the actual location of the
20854 // dragged element.
20855 var dc = this.dragCurrent;
20856 if (!dc || !dc.getTargetCoord ||
20857 (!intersect && !dc.constrainX && !dc.constrainY)) {
20858 return oTarget.cursorIsOver;
20861 oTarget.overlap = null;
20863 // Get the current location of the drag element, this is the
20864 // location of the mouse event less the delta that represents
20865 // where the original mousedown happened on the element. We
20866 // need to consider constraints and ticks as well.
20867 var pos = dc.getTargetCoord(pt.x, pt.y);
20869 var el = dc.getDragEl();
20870 var curRegion = new Roo.lib.Region( pos.y,
20871 pos.x + el.offsetWidth,
20872 pos.y + el.offsetHeight,
20875 var overlap = curRegion.intersect(loc);
20878 oTarget.overlap = overlap;
20879 return (intersect) ? true : oTarget.cursorIsOver;
20886 * unload event handler
20887 * @method _onUnload
20891 _onUnload: function(e, me) {
20892 Roo.dd.DragDropMgr.unregAll();
20896 * Cleans up the drag and drop events and objects.
20901 unregAll: function() {
20903 if (this.dragCurrent) {
20905 this.dragCurrent = null;
20908 this._execOnAll("unreg", []);
20910 for (i in this.elementCache) {
20911 delete this.elementCache[i];
20914 this.elementCache = {};
20919 * A cache of DOM elements
20920 * @property elementCache
20927 * Get the wrapper for the DOM element specified
20928 * @method getElWrapper
20929 * @param {String} id the id of the element to get
20930 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20932 * @deprecated This wrapper isn't that useful
20935 getElWrapper: function(id) {
20936 var oWrapper = this.elementCache[id];
20937 if (!oWrapper || !oWrapper.el) {
20938 oWrapper = this.elementCache[id] =
20939 new this.ElementWrapper(Roo.getDom(id));
20945 * Returns the actual DOM element
20946 * @method getElement
20947 * @param {String} id the id of the elment to get
20948 * @return {Object} The element
20949 * @deprecated use Roo.getDom instead
20952 getElement: function(id) {
20953 return Roo.getDom(id);
20957 * Returns the style property for the DOM element (i.e.,
20958 * document.getElById(id).style)
20960 * @param {String} id the id of the elment to get
20961 * @return {Object} The style property of the element
20962 * @deprecated use Roo.getDom instead
20965 getCss: function(id) {
20966 var el = Roo.getDom(id);
20967 return (el) ? el.style : null;
20971 * Inner class for cached elements
20972 * @class DragDropMgr.ElementWrapper
20977 ElementWrapper: function(el) {
20982 this.el = el || null;
20987 this.id = this.el && el.id;
20989 * A reference to the style property
20992 this.css = this.el && el.style;
20996 * Returns the X position of an html element
20998 * @param el the element for which to get the position
20999 * @return {int} the X coordinate
21001 * @deprecated use Roo.lib.Dom.getX instead
21004 getPosX: function(el) {
21005 return Roo.lib.Dom.getX(el);
21009 * Returns the Y position of an html element
21011 * @param el the element for which to get the position
21012 * @return {int} the Y coordinate
21013 * @deprecated use Roo.lib.Dom.getY instead
21016 getPosY: function(el) {
21017 return Roo.lib.Dom.getY(el);
21021 * Swap two nodes. In IE, we use the native method, for others we
21022 * emulate the IE behavior
21024 * @param n1 the first node to swap
21025 * @param n2 the other node to swap
21028 swapNode: function(n1, n2) {
21032 var p = n2.parentNode;
21033 var s = n2.nextSibling;
21036 p.insertBefore(n1, n2);
21037 } else if (n2 == n1.nextSibling) {
21038 p.insertBefore(n2, n1);
21040 n1.parentNode.replaceChild(n2, n1);
21041 p.insertBefore(n1, s);
21047 * Returns the current scroll position
21048 * @method getScroll
21052 getScroll: function () {
21053 var t, l, dde=document.documentElement, db=document.body;
21054 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21056 l = dde.scrollLeft;
21063 return { top: t, left: l };
21067 * Returns the specified element style property
21069 * @param {HTMLElement} el the element
21070 * @param {string} styleProp the style property
21071 * @return {string} The value of the style property
21072 * @deprecated use Roo.lib.Dom.getStyle
21075 getStyle: function(el, styleProp) {
21076 return Roo.fly(el).getStyle(styleProp);
21080 * Gets the scrollTop
21081 * @method getScrollTop
21082 * @return {int} the document's scrollTop
21085 getScrollTop: function () { return this.getScroll().top; },
21088 * Gets the scrollLeft
21089 * @method getScrollLeft
21090 * @return {int} the document's scrollTop
21093 getScrollLeft: function () { return this.getScroll().left; },
21096 * Sets the x/y position of an element to the location of the
21099 * @param {HTMLElement} moveEl The element to move
21100 * @param {HTMLElement} targetEl The position reference element
21103 moveToEl: function (moveEl, targetEl) {
21104 var aCoord = Roo.lib.Dom.getXY(targetEl);
21105 Roo.lib.Dom.setXY(moveEl, aCoord);
21109 * Numeric array sort function
21110 * @method numericSort
21113 numericSort: function(a, b) { return (a - b); },
21117 * @property _timeoutCount
21124 * Trying to make the load order less important. Without this we get
21125 * an error if this file is loaded before the Event Utility.
21126 * @method _addListeners
21130 _addListeners: function() {
21131 var DDM = Roo.dd.DDM;
21132 if ( Roo.lib.Event && document ) {
21135 if (DDM._timeoutCount > 2000) {
21137 setTimeout(DDM._addListeners, 10);
21138 if (document && document.body) {
21139 DDM._timeoutCount += 1;
21146 * Recursively searches the immediate parent and all child nodes for
21147 * the handle element in order to determine wheter or not it was
21149 * @method handleWasClicked
21150 * @param node the html element to inspect
21153 handleWasClicked: function(node, id) {
21154 if (this.isHandle(id, node.id)) {
21157 // check to see if this is a text node child of the one we want
21158 var p = node.parentNode;
21161 if (this.isHandle(id, p.id)) {
21176 // shorter alias, save a few bytes
21177 Roo.dd.DDM = Roo.dd.DragDropMgr;
21178 Roo.dd.DDM._addListeners();
21182 * Ext JS Library 1.1.1
21183 * Copyright(c) 2006-2007, Ext JS, LLC.
21185 * Originally Released Under LGPL - original licence link has changed is not relivant.
21188 * <script type="text/javascript">
21193 * A DragDrop implementation where the linked element follows the
21194 * mouse cursor during a drag.
21195 * @extends Roo.dd.DragDrop
21197 * @param {String} id the id of the linked element
21198 * @param {String} sGroup the group of related DragDrop items
21199 * @param {object} config an object containing configurable attributes
21200 * Valid properties for DD:
21203 Roo.dd.DD = function(id, sGroup, config) {
21205 this.init(id, sGroup, config);
21209 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21212 * When set to true, the utility automatically tries to scroll the browser
21213 * window wehn a drag and drop element is dragged near the viewport boundary.
21214 * Defaults to true.
21221 * Sets the pointer offset to the distance between the linked element's top
21222 * left corner and the location the element was clicked
21223 * @method autoOffset
21224 * @param {int} iPageX the X coordinate of the click
21225 * @param {int} iPageY the Y coordinate of the click
21227 autoOffset: function(iPageX, iPageY) {
21228 var x = iPageX - this.startPageX;
21229 var y = iPageY - this.startPageY;
21230 this.setDelta(x, y);
21234 * Sets the pointer offset. You can call this directly to force the
21235 * offset to be in a particular location (e.g., pass in 0,0 to set it
21236 * to the center of the object)
21238 * @param {int} iDeltaX the distance from the left
21239 * @param {int} iDeltaY the distance from the top
21241 setDelta: function(iDeltaX, iDeltaY) {
21242 this.deltaX = iDeltaX;
21243 this.deltaY = iDeltaY;
21247 * Sets the drag element to the location of the mousedown or click event,
21248 * maintaining the cursor location relative to the location on the element
21249 * that was clicked. Override this if you want to place the element in a
21250 * location other than where the cursor is.
21251 * @method setDragElPos
21252 * @param {int} iPageX the X coordinate of the mousedown or drag event
21253 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21255 setDragElPos: function(iPageX, iPageY) {
21256 // the first time we do this, we are going to check to make sure
21257 // the element has css positioning
21259 var el = this.getDragEl();
21260 this.alignElWithMouse(el, iPageX, iPageY);
21264 * Sets the element to the location of the mousedown or click event,
21265 * maintaining the cursor location relative to the location on the element
21266 * that was clicked. Override this if you want to place the element in a
21267 * location other than where the cursor is.
21268 * @method alignElWithMouse
21269 * @param {HTMLElement} el the element to move
21270 * @param {int} iPageX the X coordinate of the mousedown or drag event
21271 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21273 alignElWithMouse: function(el, iPageX, iPageY) {
21274 var oCoord = this.getTargetCoord(iPageX, iPageY);
21275 var fly = el.dom ? el : Roo.fly(el);
21276 if (!this.deltaSetXY) {
21277 var aCoord = [oCoord.x, oCoord.y];
21279 var newLeft = fly.getLeft(true);
21280 var newTop = fly.getTop(true);
21281 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21283 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21286 this.cachePosition(oCoord.x, oCoord.y);
21287 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21292 * Saves the most recent position so that we can reset the constraints and
21293 * tick marks on-demand. We need to know this so that we can calculate the
21294 * number of pixels the element is offset from its original position.
21295 * @method cachePosition
21296 * @param iPageX the current x position (optional, this just makes it so we
21297 * don't have to look it up again)
21298 * @param iPageY the current y position (optional, this just makes it so we
21299 * don't have to look it up again)
21301 cachePosition: function(iPageX, iPageY) {
21303 this.lastPageX = iPageX;
21304 this.lastPageY = iPageY;
21306 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21307 this.lastPageX = aCoord[0];
21308 this.lastPageY = aCoord[1];
21313 * Auto-scroll the window if the dragged object has been moved beyond the
21314 * visible window boundary.
21315 * @method autoScroll
21316 * @param {int} x the drag element's x position
21317 * @param {int} y the drag element's y position
21318 * @param {int} h the height of the drag element
21319 * @param {int} w the width of the drag element
21322 autoScroll: function(x, y, h, w) {
21325 // The client height
21326 var clientH = Roo.lib.Dom.getViewWidth();
21328 // The client width
21329 var clientW = Roo.lib.Dom.getViewHeight();
21331 // The amt scrolled down
21332 var st = this.DDM.getScrollTop();
21334 // The amt scrolled right
21335 var sl = this.DDM.getScrollLeft();
21337 // Location of the bottom of the element
21340 // Location of the right of the element
21343 // The distance from the cursor to the bottom of the visible area,
21344 // adjusted so that we don't scroll if the cursor is beyond the
21345 // element drag constraints
21346 var toBot = (clientH + st - y - this.deltaY);
21348 // The distance from the cursor to the right of the visible area
21349 var toRight = (clientW + sl - x - this.deltaX);
21352 // How close to the edge the cursor must be before we scroll
21353 // var thresh = (document.all) ? 100 : 40;
21356 // How many pixels to scroll per autoscroll op. This helps to reduce
21357 // clunky scrolling. IE is more sensitive about this ... it needs this
21358 // value to be higher.
21359 var scrAmt = (document.all) ? 80 : 30;
21361 // Scroll down if we are near the bottom of the visible page and the
21362 // obj extends below the crease
21363 if ( bot > clientH && toBot < thresh ) {
21364 window.scrollTo(sl, st + scrAmt);
21367 // Scroll up if the window is scrolled down and the top of the object
21368 // goes above the top border
21369 if ( y < st && st > 0 && y - st < thresh ) {
21370 window.scrollTo(sl, st - scrAmt);
21373 // Scroll right if the obj is beyond the right border and the cursor is
21374 // near the border.
21375 if ( right > clientW && toRight < thresh ) {
21376 window.scrollTo(sl + scrAmt, st);
21379 // Scroll left if the window has been scrolled to the right and the obj
21380 // extends past the left border
21381 if ( x < sl && sl > 0 && x - sl < thresh ) {
21382 window.scrollTo(sl - scrAmt, st);
21388 * Finds the location the element should be placed if we want to move
21389 * it to where the mouse location less the click offset would place us.
21390 * @method getTargetCoord
21391 * @param {int} iPageX the X coordinate of the click
21392 * @param {int} iPageY the Y coordinate of the click
21393 * @return an object that contains the coordinates (Object.x and Object.y)
21396 getTargetCoord: function(iPageX, iPageY) {
21399 var x = iPageX - this.deltaX;
21400 var y = iPageY - this.deltaY;
21402 if (this.constrainX) {
21403 if (x < this.minX) { x = this.minX; }
21404 if (x > this.maxX) { x = this.maxX; }
21407 if (this.constrainY) {
21408 if (y < this.minY) { y = this.minY; }
21409 if (y > this.maxY) { y = this.maxY; }
21412 x = this.getTick(x, this.xTicks);
21413 y = this.getTick(y, this.yTicks);
21420 * Sets up config options specific to this class. Overrides
21421 * Roo.dd.DragDrop, but all versions of this method through the
21422 * inheritance chain are called
21424 applyConfig: function() {
21425 Roo.dd.DD.superclass.applyConfig.call(this);
21426 this.scroll = (this.config.scroll !== false);
21430 * Event that fires prior to the onMouseDown event. Overrides
21433 b4MouseDown: function(e) {
21434 // this.resetConstraints();
21435 this.autoOffset(e.getPageX(),
21440 * Event that fires prior to the onDrag event. Overrides
21443 b4Drag: function(e) {
21444 this.setDragElPos(e.getPageX(),
21448 toString: function() {
21449 return ("DD " + this.id);
21452 //////////////////////////////////////////////////////////////////////////
21453 // Debugging ygDragDrop events that can be overridden
21454 //////////////////////////////////////////////////////////////////////////
21456 startDrag: function(x, y) {
21459 onDrag: function(e) {
21462 onDragEnter: function(e, id) {
21465 onDragOver: function(e, id) {
21468 onDragOut: function(e, id) {
21471 onDragDrop: function(e, id) {
21474 endDrag: function(e) {
21481 * Ext JS Library 1.1.1
21482 * Copyright(c) 2006-2007, Ext JS, LLC.
21484 * Originally Released Under LGPL - original licence link has changed is not relivant.
21487 * <script type="text/javascript">
21491 * @class Roo.dd.DDProxy
21492 * A DragDrop implementation that inserts an empty, bordered div into
21493 * the document that follows the cursor during drag operations. At the time of
21494 * the click, the frame div is resized to the dimensions of the linked html
21495 * element, and moved to the exact location of the linked element.
21497 * References to the "frame" element refer to the single proxy element that
21498 * was created to be dragged in place of all DDProxy elements on the
21501 * @extends Roo.dd.DD
21503 * @param {String} id the id of the linked html element
21504 * @param {String} sGroup the group of related DragDrop objects
21505 * @param {object} config an object containing configurable attributes
21506 * Valid properties for DDProxy in addition to those in DragDrop:
21507 * resizeFrame, centerFrame, dragElId
21509 Roo.dd.DDProxy = function(id, sGroup, config) {
21511 this.init(id, sGroup, config);
21517 * The default drag frame div id
21518 * @property Roo.dd.DDProxy.dragElId
21522 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21524 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21527 * By default we resize the drag frame to be the same size as the element
21528 * we want to drag (this is to get the frame effect). We can turn it off
21529 * if we want a different behavior.
21530 * @property resizeFrame
21536 * By default the frame is positioned exactly where the drag element is, so
21537 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21538 * you do not have constraints on the obj is to have the drag frame centered
21539 * around the cursor. Set centerFrame to true for this effect.
21540 * @property centerFrame
21543 centerFrame: false,
21546 * Creates the proxy element if it does not yet exist
21547 * @method createFrame
21549 createFrame: function() {
21551 var body = document.body;
21553 if (!body || !body.firstChild) {
21554 setTimeout( function() { self.createFrame(); }, 50 );
21558 var div = this.getDragEl();
21561 div = document.createElement("div");
21562 div.id = this.dragElId;
21565 s.position = "absolute";
21566 s.visibility = "hidden";
21568 s.border = "2px solid #aaa";
21571 // appendChild can blow up IE if invoked prior to the window load event
21572 // while rendering a table. It is possible there are other scenarios
21573 // that would cause this to happen as well.
21574 body.insertBefore(div, body.firstChild);
21579 * Initialization for the drag frame element. Must be called in the
21580 * constructor of all subclasses
21581 * @method initFrame
21583 initFrame: function() {
21584 this.createFrame();
21587 applyConfig: function() {
21588 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21590 this.resizeFrame = (this.config.resizeFrame !== false);
21591 this.centerFrame = (this.config.centerFrame);
21592 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21596 * Resizes the drag frame to the dimensions of the clicked object, positions
21597 * it over the object, and finally displays it
21598 * @method showFrame
21599 * @param {int} iPageX X click position
21600 * @param {int} iPageY Y click position
21603 showFrame: function(iPageX, iPageY) {
21604 var el = this.getEl();
21605 var dragEl = this.getDragEl();
21606 var s = dragEl.style;
21608 this._resizeProxy();
21610 if (this.centerFrame) {
21611 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21612 Math.round(parseInt(s.height, 10)/2) );
21615 this.setDragElPos(iPageX, iPageY);
21617 Roo.fly(dragEl).show();
21621 * The proxy is automatically resized to the dimensions of the linked
21622 * element when a drag is initiated, unless resizeFrame is set to false
21623 * @method _resizeProxy
21626 _resizeProxy: function() {
21627 if (this.resizeFrame) {
21628 var el = this.getEl();
21629 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21633 // overrides Roo.dd.DragDrop
21634 b4MouseDown: function(e) {
21635 var x = e.getPageX();
21636 var y = e.getPageY();
21637 this.autoOffset(x, y);
21638 this.setDragElPos(x, y);
21641 // overrides Roo.dd.DragDrop
21642 b4StartDrag: function(x, y) {
21643 // show the drag frame
21644 this.showFrame(x, y);
21647 // overrides Roo.dd.DragDrop
21648 b4EndDrag: function(e) {
21649 Roo.fly(this.getDragEl()).hide();
21652 // overrides Roo.dd.DragDrop
21653 // By default we try to move the element to the last location of the frame.
21654 // This is so that the default behavior mirrors that of Roo.dd.DD.
21655 endDrag: function(e) {
21657 var lel = this.getEl();
21658 var del = this.getDragEl();
21660 // Show the drag frame briefly so we can get its position
21661 del.style.visibility = "";
21664 // Hide the linked element before the move to get around a Safari
21666 lel.style.visibility = "hidden";
21667 Roo.dd.DDM.moveToEl(lel, del);
21668 del.style.visibility = "hidden";
21669 lel.style.visibility = "";
21674 beforeMove : function(){
21678 afterDrag : function(){
21682 toString: function() {
21683 return ("DDProxy " + this.id);
21689 * Ext JS Library 1.1.1
21690 * Copyright(c) 2006-2007, Ext JS, LLC.
21692 * Originally Released Under LGPL - original licence link has changed is not relivant.
21695 * <script type="text/javascript">
21699 * @class Roo.dd.DDTarget
21700 * A DragDrop implementation that does not move, but can be a drop
21701 * target. You would get the same result by simply omitting implementation
21702 * for the event callbacks, but this way we reduce the processing cost of the
21703 * event listener and the callbacks.
21704 * @extends Roo.dd.DragDrop
21706 * @param {String} id the id of the element that is a drop target
21707 * @param {String} sGroup the group of related DragDrop objects
21708 * @param {object} config an object containing configurable attributes
21709 * Valid properties for DDTarget in addition to those in
21713 Roo.dd.DDTarget = function(id, sGroup, config) {
21715 this.initTarget(id, sGroup, config);
21717 if (config && (config.listeners || config.events)) {
21718 Roo.dd.DragDrop.superclass.constructor.call(this, {
21719 listeners : config.listeners || {},
21720 events : config.events || {}
21725 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21726 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21727 toString: function() {
21728 return ("DDTarget " + this.id);
21733 * Ext JS Library 1.1.1
21734 * Copyright(c) 2006-2007, Ext JS, LLC.
21736 * Originally Released Under LGPL - original licence link has changed is not relivant.
21739 * <script type="text/javascript">
21744 * @class Roo.dd.ScrollManager
21745 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21746 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21749 Roo.dd.ScrollManager = function(){
21750 var ddm = Roo.dd.DragDropMgr;
21757 var onStop = function(e){
21762 var triggerRefresh = function(){
21763 if(ddm.dragCurrent){
21764 ddm.refreshCache(ddm.dragCurrent.groups);
21768 var doScroll = function(){
21769 if(ddm.dragCurrent){
21770 var dds = Roo.dd.ScrollManager;
21772 if(proc.el.scroll(proc.dir, dds.increment)){
21776 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21781 var clearProc = function(){
21783 clearInterval(proc.id);
21790 var startProc = function(el, dir){
21791 Roo.log('scroll startproc');
21795 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21798 var onFire = function(e, isDrop){
21800 if(isDrop || !ddm.dragCurrent){ return; }
21801 var dds = Roo.dd.ScrollManager;
21802 if(!dragEl || dragEl != ddm.dragCurrent){
21803 dragEl = ddm.dragCurrent;
21804 // refresh regions on drag start
21805 dds.refreshCache();
21808 var xy = Roo.lib.Event.getXY(e);
21809 var pt = new Roo.lib.Point(xy[0], xy[1]);
21810 for(var id in els){
21811 var el = els[id], r = el._region;
21812 if(r && r.contains(pt) && el.isScrollable()){
21813 if(r.bottom - pt.y <= dds.thresh){
21815 startProc(el, "down");
21818 }else if(r.right - pt.x <= dds.thresh){
21820 startProc(el, "left");
21823 }else if(pt.y - r.top <= dds.thresh){
21825 startProc(el, "up");
21828 }else if(pt.x - r.left <= dds.thresh){
21830 startProc(el, "right");
21839 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21840 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21844 * Registers new overflow element(s) to auto scroll
21845 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21847 register : function(el){
21848 if(el instanceof Array){
21849 for(var i = 0, len = el.length; i < len; i++) {
21850 this.register(el[i]);
21856 Roo.dd.ScrollManager.els = els;
21860 * Unregisters overflow element(s) so they are no longer scrolled
21861 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21863 unregister : function(el){
21864 if(el instanceof Array){
21865 for(var i = 0, len = el.length; i < len; i++) {
21866 this.unregister(el[i]);
21875 * The number of pixels from the edge of a container the pointer needs to be to
21876 * trigger scrolling (defaults to 25)
21882 * The number of pixels to scroll in each scroll increment (defaults to 50)
21888 * The frequency of scrolls in milliseconds (defaults to 500)
21894 * True to animate the scroll (defaults to true)
21900 * The animation duration in seconds -
21901 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21907 * Manually trigger a cache refresh.
21909 refreshCache : function(){
21910 for(var id in els){
21911 if(typeof els[id] == 'object'){ // for people extending the object prototype
21912 els[id]._region = els[id].getRegion();
21919 * Ext JS Library 1.1.1
21920 * Copyright(c) 2006-2007, Ext JS, LLC.
21922 * Originally Released Under LGPL - original licence link has changed is not relivant.
21925 * <script type="text/javascript">
21930 * @class Roo.dd.Registry
21931 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21932 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21935 Roo.dd.Registry = function(){
21938 var autoIdSeed = 0;
21940 var getId = function(el, autogen){
21941 if(typeof el == "string"){
21945 if(!id && autogen !== false){
21946 id = "roodd-" + (++autoIdSeed);
21954 * Register a drag drop element
21955 * @param {String|HTMLElement} element The id or DOM node to register
21956 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21957 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21958 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21959 * populated in the data object (if applicable):
21961 Value Description<br />
21962 --------- ------------------------------------------<br />
21963 handles Array of DOM nodes that trigger dragging<br />
21964 for the element being registered<br />
21965 isHandle True if the element passed in triggers<br />
21966 dragging itself, else false
21969 register : function(el, data){
21971 if(typeof el == "string"){
21972 el = document.getElementById(el);
21975 elements[getId(el)] = data;
21976 if(data.isHandle !== false){
21977 handles[data.ddel.id] = data;
21980 var hs = data.handles;
21981 for(var i = 0, len = hs.length; i < len; i++){
21982 handles[getId(hs[i])] = data;
21988 * Unregister a drag drop element
21989 * @param {String|HTMLElement} element The id or DOM node to unregister
21991 unregister : function(el){
21992 var id = getId(el, false);
21993 var data = elements[id];
21995 delete elements[id];
21997 var hs = data.handles;
21998 for(var i = 0, len = hs.length; i < len; i++){
21999 delete handles[getId(hs[i], false)];
22006 * Returns the handle registered for a DOM Node by id
22007 * @param {String|HTMLElement} id The DOM node or id to look up
22008 * @return {Object} handle The custom handle data
22010 getHandle : function(id){
22011 if(typeof id != "string"){ // must be element?
22014 return handles[id];
22018 * Returns the handle that is registered for the DOM node that is the target of the event
22019 * @param {Event} e The event
22020 * @return {Object} handle The custom handle data
22022 getHandleFromEvent : function(e){
22023 var t = Roo.lib.Event.getTarget(e);
22024 return t ? handles[t.id] : null;
22028 * Returns a custom data object that is registered for a DOM node by id
22029 * @param {String|HTMLElement} id The DOM node or id to look up
22030 * @return {Object} data The custom data
22032 getTarget : function(id){
22033 if(typeof id != "string"){ // must be element?
22036 return elements[id];
22040 * Returns a custom data object that is registered for the DOM node that is the target of the event
22041 * @param {Event} e The event
22042 * @return {Object} data The custom data
22044 getTargetFromEvent : function(e){
22045 var t = Roo.lib.Event.getTarget(e);
22046 return t ? elements[t.id] || handles[t.id] : null;
22051 * Ext JS Library 1.1.1
22052 * Copyright(c) 2006-2007, Ext JS, LLC.
22054 * Originally Released Under LGPL - original licence link has changed is not relivant.
22057 * <script type="text/javascript">
22062 * @class Roo.dd.StatusProxy
22063 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22064 * default drag proxy used by all Roo.dd components.
22066 * @param {Object} config
22068 Roo.dd.StatusProxy = function(config){
22069 Roo.apply(this, config);
22070 this.id = this.id || Roo.id();
22071 this.el = new Roo.Layer({
22073 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22074 {tag: "div", cls: "x-dd-drop-icon"},
22075 {tag: "div", cls: "x-dd-drag-ghost"}
22078 shadow: !config || config.shadow !== false
22080 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22081 this.dropStatus = this.dropNotAllowed;
22084 Roo.dd.StatusProxy.prototype = {
22086 * @cfg {String} dropAllowed
22087 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22089 dropAllowed : "x-dd-drop-ok",
22091 * @cfg {String} dropNotAllowed
22092 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22094 dropNotAllowed : "x-dd-drop-nodrop",
22097 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22098 * over the current target element.
22099 * @param {String} cssClass The css class for the new drop status indicator image
22101 setStatus : function(cssClass){
22102 cssClass = cssClass || this.dropNotAllowed;
22103 if(this.dropStatus != cssClass){
22104 this.el.replaceClass(this.dropStatus, cssClass);
22105 this.dropStatus = cssClass;
22110 * Resets the status indicator to the default dropNotAllowed value
22111 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22113 reset : function(clearGhost){
22114 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22115 this.dropStatus = this.dropNotAllowed;
22117 this.ghost.update("");
22122 * Updates the contents of the ghost element
22123 * @param {String} html The html that will replace the current innerHTML of the ghost element
22125 update : function(html){
22126 if(typeof html == "string"){
22127 this.ghost.update(html);
22129 this.ghost.update("");
22130 html.style.margin = "0";
22131 this.ghost.dom.appendChild(html);
22133 // ensure float = none set?? cant remember why though.
22134 var el = this.ghost.dom.firstChild;
22136 Roo.fly(el).setStyle('float', 'none');
22141 * Returns the underlying proxy {@link Roo.Layer}
22142 * @return {Roo.Layer} el
22144 getEl : function(){
22149 * Returns the ghost element
22150 * @return {Roo.Element} el
22152 getGhost : function(){
22158 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22160 hide : function(clear){
22168 * Stops the repair animation if it's currently running
22171 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22177 * Displays this proxy
22184 * Force the Layer to sync its shadow and shim positions to the element
22191 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22192 * invalid drop operation by the item being dragged.
22193 * @param {Array} xy The XY position of the element ([x, y])
22194 * @param {Function} callback The function to call after the repair is complete
22195 * @param {Object} scope The scope in which to execute the callback
22197 repair : function(xy, callback, scope){
22198 this.callback = callback;
22199 this.scope = scope;
22200 if(xy && this.animRepair !== false){
22201 this.el.addClass("x-dd-drag-repair");
22202 this.el.hideUnders(true);
22203 this.anim = this.el.shift({
22204 duration: this.repairDuration || .5,
22208 callback: this.afterRepair,
22212 this.afterRepair();
22217 afterRepair : function(){
22219 if(typeof this.callback == "function"){
22220 this.callback.call(this.scope || this);
22222 this.callback = null;
22227 * Ext JS Library 1.1.1
22228 * Copyright(c) 2006-2007, Ext JS, LLC.
22230 * Originally Released Under LGPL - original licence link has changed is not relivant.
22233 * <script type="text/javascript">
22237 * @class Roo.dd.DragSource
22238 * @extends Roo.dd.DDProxy
22239 * A simple class that provides the basic implementation needed to make any element draggable.
22241 * @param {String/HTMLElement/Element} el The container element
22242 * @param {Object} config
22244 Roo.dd.DragSource = function(el, config){
22245 this.el = Roo.get(el);
22246 this.dragData = {};
22248 Roo.apply(this, config);
22251 this.proxy = new Roo.dd.StatusProxy();
22254 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22255 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22257 this.dragging = false;
22260 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22262 * @cfg {String} dropAllowed
22263 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22265 dropAllowed : "x-dd-drop-ok",
22267 * @cfg {String} dropNotAllowed
22268 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22270 dropNotAllowed : "x-dd-drop-nodrop",
22273 * Returns the data object associated with this drag source
22274 * @return {Object} data An object containing arbitrary data
22276 getDragData : function(e){
22277 return this.dragData;
22281 onDragEnter : function(e, id){
22282 var target = Roo.dd.DragDropMgr.getDDById(id);
22283 this.cachedTarget = target;
22284 if(this.beforeDragEnter(target, e, id) !== false){
22285 if(target.isNotifyTarget){
22286 var status = target.notifyEnter(this, e, this.dragData);
22287 this.proxy.setStatus(status);
22289 this.proxy.setStatus(this.dropAllowed);
22292 if(this.afterDragEnter){
22294 * An empty function by default, but provided so that you can perform a custom action
22295 * when the dragged item enters the drop target by providing an implementation.
22296 * @param {Roo.dd.DragDrop} target The drop target
22297 * @param {Event} e The event object
22298 * @param {String} id The id of the dragged element
22299 * @method afterDragEnter
22301 this.afterDragEnter(target, e, id);
22307 * An empty function by default, but provided so that you can perform a custom action
22308 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22309 * @param {Roo.dd.DragDrop} target The drop target
22310 * @param {Event} e The event object
22311 * @param {String} id The id of the dragged element
22312 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22314 beforeDragEnter : function(target, e, id){
22319 alignElWithMouse: function() {
22320 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22325 onDragOver : function(e, id){
22326 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22327 if(this.beforeDragOver(target, e, id) !== false){
22328 if(target.isNotifyTarget){
22329 var status = target.notifyOver(this, e, this.dragData);
22330 this.proxy.setStatus(status);
22333 if(this.afterDragOver){
22335 * An empty function by default, but provided so that you can perform a custom action
22336 * while the dragged item is over the drop target by providing an implementation.
22337 * @param {Roo.dd.DragDrop} target The drop target
22338 * @param {Event} e The event object
22339 * @param {String} id The id of the dragged element
22340 * @method afterDragOver
22342 this.afterDragOver(target, e, id);
22348 * An empty function by default, but provided so that you can perform a custom action
22349 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22350 * @param {Roo.dd.DragDrop} target The drop target
22351 * @param {Event} e The event object
22352 * @param {String} id The id of the dragged element
22353 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22355 beforeDragOver : function(target, e, id){
22360 onDragOut : function(e, id){
22361 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22362 if(this.beforeDragOut(target, e, id) !== false){
22363 if(target.isNotifyTarget){
22364 target.notifyOut(this, e, this.dragData);
22366 this.proxy.reset();
22367 if(this.afterDragOut){
22369 * An empty function by default, but provided so that you can perform a custom action
22370 * after the dragged item is dragged out of the target without dropping.
22371 * @param {Roo.dd.DragDrop} target The drop target
22372 * @param {Event} e The event object
22373 * @param {String} id The id of the dragged element
22374 * @method afterDragOut
22376 this.afterDragOut(target, e, id);
22379 this.cachedTarget = null;
22383 * An empty function by default, but provided so that you can perform a custom action before the dragged
22384 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22385 * @param {Roo.dd.DragDrop} target The drop target
22386 * @param {Event} e The event object
22387 * @param {String} id The id of the dragged element
22388 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22390 beforeDragOut : function(target, e, id){
22395 onDragDrop : function(e, id){
22396 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22397 if(this.beforeDragDrop(target, e, id) !== false){
22398 if(target.isNotifyTarget){
22399 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22400 this.onValidDrop(target, e, id);
22402 this.onInvalidDrop(target, e, id);
22405 this.onValidDrop(target, e, id);
22408 if(this.afterDragDrop){
22410 * An empty function by default, but provided so that you can perform a custom action
22411 * after a valid drag drop has occurred by providing an implementation.
22412 * @param {Roo.dd.DragDrop} target The drop target
22413 * @param {Event} e The event object
22414 * @param {String} id The id of the dropped element
22415 * @method afterDragDrop
22417 this.afterDragDrop(target, e, id);
22420 delete this.cachedTarget;
22424 * An empty function by default, but provided so that you can perform a custom action before the dragged
22425 * item is dropped onto the target and optionally cancel the onDragDrop.
22426 * @param {Roo.dd.DragDrop} target The drop target
22427 * @param {Event} e The event object
22428 * @param {String} id The id of the dragged element
22429 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22431 beforeDragDrop : function(target, e, id){
22436 onValidDrop : function(target, e, id){
22438 if(this.afterValidDrop){
22440 * An empty function by default, but provided so that you can perform a custom action
22441 * after a valid drop has occurred by providing an implementation.
22442 * @param {Object} target The target DD
22443 * @param {Event} e The event object
22444 * @param {String} id The id of the dropped element
22445 * @method afterInvalidDrop
22447 this.afterValidDrop(target, e, id);
22452 getRepairXY : function(e, data){
22453 return this.el.getXY();
22457 onInvalidDrop : function(target, e, id){
22458 this.beforeInvalidDrop(target, e, id);
22459 if(this.cachedTarget){
22460 if(this.cachedTarget.isNotifyTarget){
22461 this.cachedTarget.notifyOut(this, e, this.dragData);
22463 this.cacheTarget = null;
22465 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22467 if(this.afterInvalidDrop){
22469 * An empty function by default, but provided so that you can perform a custom action
22470 * after an invalid drop has occurred by providing an implementation.
22471 * @param {Event} e The event object
22472 * @param {String} id The id of the dropped element
22473 * @method afterInvalidDrop
22475 this.afterInvalidDrop(e, id);
22480 afterRepair : function(){
22482 this.el.highlight(this.hlColor || "c3daf9");
22484 this.dragging = false;
22488 * An empty function by default, but provided so that you can perform a custom action after an invalid
22489 * drop has occurred.
22490 * @param {Roo.dd.DragDrop} target The drop target
22491 * @param {Event} e The event object
22492 * @param {String} id The id of the dragged element
22493 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22495 beforeInvalidDrop : function(target, e, id){
22500 handleMouseDown : function(e){
22501 if(this.dragging) {
22504 var data = this.getDragData(e);
22505 if(data && this.onBeforeDrag(data, e) !== false){
22506 this.dragData = data;
22508 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22513 * An empty function by default, but provided so that you can perform a custom action before the initial
22514 * drag event begins and optionally cancel it.
22515 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22516 * @param {Event} e The event object
22517 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22519 onBeforeDrag : function(data, e){
22524 * An empty function by default, but provided so that you can perform a custom action once the initial
22525 * drag event has begun. The drag cannot be canceled from this function.
22526 * @param {Number} x The x position of the click on the dragged object
22527 * @param {Number} y The y position of the click on the dragged object
22529 onStartDrag : Roo.emptyFn,
22531 // private - YUI override
22532 startDrag : function(x, y){
22533 this.proxy.reset();
22534 this.dragging = true;
22535 this.proxy.update("");
22536 this.onInitDrag(x, y);
22541 onInitDrag : function(x, y){
22542 var clone = this.el.dom.cloneNode(true);
22543 clone.id = Roo.id(); // prevent duplicate ids
22544 this.proxy.update(clone);
22545 this.onStartDrag(x, y);
22550 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22551 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22553 getProxy : function(){
22558 * Hides the drag source's {@link Roo.dd.StatusProxy}
22560 hideProxy : function(){
22562 this.proxy.reset(true);
22563 this.dragging = false;
22567 triggerCacheRefresh : function(){
22568 Roo.dd.DDM.refreshCache(this.groups);
22571 // private - override to prevent hiding
22572 b4EndDrag: function(e) {
22575 // private - override to prevent moving
22576 endDrag : function(e){
22577 this.onEndDrag(this.dragData, e);
22581 onEndDrag : function(data, e){
22584 // private - pin to cursor
22585 autoOffset : function(x, y) {
22586 this.setDelta(-12, -20);
22590 * Ext JS Library 1.1.1
22591 * Copyright(c) 2006-2007, Ext JS, LLC.
22593 * Originally Released Under LGPL - original licence link has changed is not relivant.
22596 * <script type="text/javascript">
22601 * @class Roo.dd.DropTarget
22602 * @extends Roo.dd.DDTarget
22603 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22604 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22606 * @param {String/HTMLElement/Element} el The container element
22607 * @param {Object} config
22609 Roo.dd.DropTarget = function(el, config){
22610 this.el = Roo.get(el);
22612 var listeners = false; ;
22613 if (config && config.listeners) {
22614 listeners= config.listeners;
22615 delete config.listeners;
22617 Roo.apply(this, config);
22619 if(this.containerScroll){
22620 Roo.dd.ScrollManager.register(this.el);
22624 * @scope Roo.dd.DropTarget
22629 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22630 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22631 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22633 * IMPORTANT : it should set this.valid to true|false
22635 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22636 * @param {Event} e The event
22637 * @param {Object} data An object containing arbitrary data supplied by the drag source
22643 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22644 * This method will be called on every mouse movement while the drag source is over the drop target.
22645 * This default implementation simply returns the dropAllowed config value.
22647 * IMPORTANT : it should set this.valid to true|false
22649 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22650 * @param {Event} e The event
22651 * @param {Object} data An object containing arbitrary data supplied by the drag source
22657 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22658 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22659 * overClass (if any) from the drop element.
22662 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22663 * @param {Event} e The event
22664 * @param {Object} data An object containing arbitrary data supplied by the drag source
22670 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22671 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22672 * implementation that does something to process the drop event and returns true so that the drag source's
22673 * repair action does not run.
22675 * IMPORTANT : it should set this.success
22677 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22678 * @param {Event} e The event
22679 * @param {Object} data An object containing arbitrary data supplied by the drag source
22685 Roo.dd.DropTarget.superclass.constructor.call( this,
22687 this.ddGroup || this.group,
22690 listeners : listeners || {}
22698 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22700 * @cfg {String} overClass
22701 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22704 * @cfg {String} ddGroup
22705 * The drag drop group to handle drop events for
22709 * @cfg {String} dropAllowed
22710 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22712 dropAllowed : "x-dd-drop-ok",
22714 * @cfg {String} dropNotAllowed
22715 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22717 dropNotAllowed : "x-dd-drop-nodrop",
22719 * @cfg {boolean} success
22720 * set this after drop listener..
22724 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22725 * if the drop point is valid for over/enter..
22732 isNotifyTarget : true,
22737 notifyEnter : function(dd, e, data)
22740 this.fireEvent('enter', dd, e, data);
22741 if(this.overClass){
22742 this.el.addClass(this.overClass);
22744 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22745 this.valid ? this.dropAllowed : this.dropNotAllowed
22752 notifyOver : function(dd, e, data)
22755 this.fireEvent('over', dd, e, data);
22756 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22757 this.valid ? this.dropAllowed : this.dropNotAllowed
22764 notifyOut : function(dd, e, data)
22766 this.fireEvent('out', dd, e, data);
22767 if(this.overClass){
22768 this.el.removeClass(this.overClass);
22775 notifyDrop : function(dd, e, data)
22777 this.success = false;
22778 this.fireEvent('drop', dd, e, data);
22779 return this.success;
22783 * Ext JS Library 1.1.1
22784 * Copyright(c) 2006-2007, Ext JS, LLC.
22786 * Originally Released Under LGPL - original licence link has changed is not relivant.
22789 * <script type="text/javascript">
22794 * @class Roo.dd.DragZone
22795 * @extends Roo.dd.DragSource
22796 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22797 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22799 * @param {String/HTMLElement/Element} el The container element
22800 * @param {Object} config
22802 Roo.dd.DragZone = function(el, config){
22803 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22804 if(this.containerScroll){
22805 Roo.dd.ScrollManager.register(this.el);
22809 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22811 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22812 * for auto scrolling during drag operations.
22815 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22816 * method after a failed drop (defaults to "c3daf9" - light blue)
22820 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22821 * for a valid target to drag based on the mouse down. Override this method
22822 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22823 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22824 * @param {EventObject} e The mouse down event
22825 * @return {Object} The dragData
22827 getDragData : function(e){
22828 return Roo.dd.Registry.getHandleFromEvent(e);
22832 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22833 * this.dragData.ddel
22834 * @param {Number} x The x position of the click on the dragged object
22835 * @param {Number} y The y position of the click on the dragged object
22836 * @return {Boolean} true to continue the drag, false to cancel
22838 onInitDrag : function(x, y){
22839 this.proxy.update(this.dragData.ddel.cloneNode(true));
22840 this.onStartDrag(x, y);
22845 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22847 afterRepair : function(){
22849 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22851 this.dragging = false;
22855 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22856 * the XY of this.dragData.ddel
22857 * @param {EventObject} e The mouse up event
22858 * @return {Array} The xy location (e.g. [100, 200])
22860 getRepairXY : function(e){
22861 return Roo.Element.fly(this.dragData.ddel).getXY();
22865 * Ext JS Library 1.1.1
22866 * Copyright(c) 2006-2007, Ext JS, LLC.
22868 * Originally Released Under LGPL - original licence link has changed is not relivant.
22871 * <script type="text/javascript">
22874 * @class Roo.dd.DropZone
22875 * @extends Roo.dd.DropTarget
22876 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22877 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22879 * @param {String/HTMLElement/Element} el The container element
22880 * @param {Object} config
22882 Roo.dd.DropZone = function(el, config){
22883 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22886 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22888 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22889 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22890 * provide your own custom lookup.
22891 * @param {Event} e The event
22892 * @return {Object} data The custom data
22894 getTargetFromEvent : function(e){
22895 return Roo.dd.Registry.getTargetFromEvent(e);
22899 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22900 * that it has registered. This method has no default implementation and should be overridden to provide
22901 * node-specific processing if necessary.
22902 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22903 * {@link #getTargetFromEvent} for this node)
22904 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22905 * @param {Event} e The event
22906 * @param {Object} data An object containing arbitrary data supplied by the drag source
22908 onNodeEnter : function(n, dd, e, data){
22913 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22914 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22915 * overridden to provide the proper feedback.
22916 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22917 * {@link #getTargetFromEvent} for this node)
22918 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22919 * @param {Event} e The event
22920 * @param {Object} data An object containing arbitrary data supplied by the drag source
22921 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22922 * underlying {@link Roo.dd.StatusProxy} can be updated
22924 onNodeOver : function(n, dd, e, data){
22925 return this.dropAllowed;
22929 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22930 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22931 * node-specific processing if necessary.
22932 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22933 * {@link #getTargetFromEvent} for this node)
22934 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22935 * @param {Event} e The event
22936 * @param {Object} data An object containing arbitrary data supplied by the drag source
22938 onNodeOut : function(n, dd, e, data){
22943 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22944 * the drop node. The default implementation returns false, so it should be overridden to provide the
22945 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22946 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22947 * {@link #getTargetFromEvent} for this node)
22948 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22949 * @param {Event} e The event
22950 * @param {Object} data An object containing arbitrary data supplied by the drag source
22951 * @return {Boolean} True if the drop was valid, else false
22953 onNodeDrop : function(n, dd, e, data){
22958 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22959 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22960 * it should be overridden to provide the proper feedback if necessary.
22961 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22962 * @param {Event} e The event
22963 * @param {Object} data An object containing arbitrary data supplied by the drag source
22964 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22965 * underlying {@link Roo.dd.StatusProxy} can be updated
22967 onContainerOver : function(dd, e, data){
22968 return this.dropNotAllowed;
22972 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22973 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22974 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22975 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22976 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22977 * @param {Event} e The event
22978 * @param {Object} data An object containing arbitrary data supplied by the drag source
22979 * @return {Boolean} True if the drop was valid, else false
22981 onContainerDrop : function(dd, e, data){
22986 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22987 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22988 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22989 * you should override this method and provide a custom implementation.
22990 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22991 * @param {Event} e The event
22992 * @param {Object} data An object containing arbitrary data supplied by the drag source
22993 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22994 * underlying {@link Roo.dd.StatusProxy} can be updated
22996 notifyEnter : function(dd, e, data){
22997 return this.dropNotAllowed;
23001 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23002 * This method will be called on every mouse movement while the drag source is over the drop zone.
23003 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23004 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23005 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23006 * registered node, it will call {@link #onContainerOver}.
23007 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23008 * @param {Event} e The event
23009 * @param {Object} data An object containing arbitrary data supplied by the drag source
23010 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23011 * underlying {@link Roo.dd.StatusProxy} can be updated
23013 notifyOver : function(dd, e, data){
23014 var n = this.getTargetFromEvent(e);
23015 if(!n){ // not over valid drop target
23016 if(this.lastOverNode){
23017 this.onNodeOut(this.lastOverNode, dd, e, data);
23018 this.lastOverNode = null;
23020 return this.onContainerOver(dd, e, data);
23022 if(this.lastOverNode != n){
23023 if(this.lastOverNode){
23024 this.onNodeOut(this.lastOverNode, dd, e, data);
23026 this.onNodeEnter(n, dd, e, data);
23027 this.lastOverNode = n;
23029 return this.onNodeOver(n, dd, e, data);
23033 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23034 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23035 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23036 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23037 * @param {Event} e The event
23038 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23040 notifyOut : function(dd, e, data){
23041 if(this.lastOverNode){
23042 this.onNodeOut(this.lastOverNode, dd, e, data);
23043 this.lastOverNode = null;
23048 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23049 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23050 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23051 * otherwise it will call {@link #onContainerDrop}.
23052 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23053 * @param {Event} e The event
23054 * @param {Object} data An object containing arbitrary data supplied by the drag source
23055 * @return {Boolean} True if the drop was valid, else false
23057 notifyDrop : function(dd, e, data){
23058 if(this.lastOverNode){
23059 this.onNodeOut(this.lastOverNode, dd, e, data);
23060 this.lastOverNode = null;
23062 var n = this.getTargetFromEvent(e);
23064 this.onNodeDrop(n, dd, e, data) :
23065 this.onContainerDrop(dd, e, data);
23069 triggerCacheRefresh : function(){
23070 Roo.dd.DDM.refreshCache(this.groups);
23074 * Ext JS Library 1.1.1
23075 * Copyright(c) 2006-2007, Ext JS, LLC.
23077 * Originally Released Under LGPL - original licence link has changed is not relivant.
23080 * <script type="text/javascript">
23085 * @class Roo.data.SortTypes
23087 * Defines the default sorting (casting?) comparison functions used when sorting data.
23089 Roo.data.SortTypes = {
23091 * Default sort that does nothing
23092 * @param {Mixed} s The value being converted
23093 * @return {Mixed} The comparison value
23095 none : function(s){
23100 * The regular expression used to strip tags
23104 stripTagsRE : /<\/?[^>]+>/gi,
23107 * Strips all HTML tags to sort on text only
23108 * @param {Mixed} s The value being converted
23109 * @return {String} The comparison value
23111 asText : function(s){
23112 return String(s).replace(this.stripTagsRE, "");
23116 * Strips all HTML tags to sort on text only - Case insensitive
23117 * @param {Mixed} s The value being converted
23118 * @return {String} The comparison value
23120 asUCText : function(s){
23121 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23125 * Case insensitive string
23126 * @param {Mixed} s The value being converted
23127 * @return {String} The comparison value
23129 asUCString : function(s) {
23130 return String(s).toUpperCase();
23135 * @param {Mixed} s The value being converted
23136 * @return {Number} The comparison value
23138 asDate : function(s) {
23142 if(s instanceof Date){
23143 return s.getTime();
23145 return Date.parse(String(s));
23150 * @param {Mixed} s The value being converted
23151 * @return {Float} The comparison value
23153 asFloat : function(s) {
23154 var val = parseFloat(String(s).replace(/,/g, ""));
23163 * @param {Mixed} s The value being converted
23164 * @return {Number} The comparison value
23166 asInt : function(s) {
23167 var val = parseInt(String(s).replace(/,/g, ""));
23175 * Ext JS Library 1.1.1
23176 * Copyright(c) 2006-2007, Ext JS, LLC.
23178 * Originally Released Under LGPL - original licence link has changed is not relivant.
23181 * <script type="text/javascript">
23185 * @class Roo.data.Record
23186 * Instances of this class encapsulate both record <em>definition</em> information, and record
23187 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
23188 * to access Records cached in an {@link Roo.data.Store} object.<br>
23190 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
23191 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
23194 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
23196 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
23197 * {@link #create}. The parameters are the same.
23198 * @param {Array} data An associative Array of data values keyed by the field name.
23199 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
23200 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
23201 * not specified an integer id is generated.
23203 Roo.data.Record = function(data, id){
23204 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
23209 * Generate a constructor for a specific record layout.
23210 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
23211 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
23212 * Each field definition object may contain the following properties: <ul>
23213 * <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,
23214 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
23215 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
23216 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
23217 * is being used, then this is a string containing the javascript expression to reference the data relative to
23218 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
23219 * to the data item relative to the record element. If the mapping expression is the same as the field name,
23220 * this may be omitted.</p></li>
23221 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
23222 * <ul><li>auto (Default, implies no conversion)</li>
23227 * <li>date</li></ul></p></li>
23228 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
23229 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
23230 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
23231 * by the Reader into an object that will be stored in the Record. It is passed the
23232 * following parameters:<ul>
23233 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
23235 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
23237 * <br>usage:<br><pre><code>
23238 var TopicRecord = Roo.data.Record.create(
23239 {name: 'title', mapping: 'topic_title'},
23240 {name: 'author', mapping: 'username'},
23241 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
23242 {name: 'lastPost', mapping: 'post_time', type: 'date'},
23243 {name: 'lastPoster', mapping: 'user2'},
23244 {name: 'excerpt', mapping: 'post_text'}
23247 var myNewRecord = new TopicRecord({
23248 title: 'Do my job please',
23251 lastPost: new Date(),
23252 lastPoster: 'Animal',
23253 excerpt: 'No way dude!'
23255 myStore.add(myNewRecord);
23260 Roo.data.Record.create = function(o){
23261 var f = function(){
23262 f.superclass.constructor.apply(this, arguments);
23264 Roo.extend(f, Roo.data.Record);
23265 var p = f.prototype;
23266 p.fields = new Roo.util.MixedCollection(false, function(field){
23269 for(var i = 0, len = o.length; i < len; i++){
23270 p.fields.add(new Roo.data.Field(o[i]));
23272 f.getField = function(name){
23273 return p.fields.get(name);
23278 Roo.data.Record.AUTO_ID = 1000;
23279 Roo.data.Record.EDIT = 'edit';
23280 Roo.data.Record.REJECT = 'reject';
23281 Roo.data.Record.COMMIT = 'commit';
23283 Roo.data.Record.prototype = {
23285 * Readonly flag - true if this record has been modified.
23294 join : function(store){
23295 this.store = store;
23299 * Set the named field to the specified value.
23300 * @param {String} name The name of the field to set.
23301 * @param {Object} value The value to set the field to.
23303 set : function(name, value){
23304 if(this.data[name] == value){
23308 if(!this.modified){
23309 this.modified = {};
23311 if(typeof this.modified[name] == 'undefined'){
23312 this.modified[name] = this.data[name];
23314 this.data[name] = value;
23315 if(!this.editing && this.store){
23316 this.store.afterEdit(this);
23321 * Get the value of the named field.
23322 * @param {String} name The name of the field to get the value of.
23323 * @return {Object} The value of the field.
23325 get : function(name){
23326 return this.data[name];
23330 beginEdit : function(){
23331 this.editing = true;
23332 this.modified = {};
23336 cancelEdit : function(){
23337 this.editing = false;
23338 delete this.modified;
23342 endEdit : function(){
23343 this.editing = false;
23344 if(this.dirty && this.store){
23345 this.store.afterEdit(this);
23350 * Usually called by the {@link Roo.data.Store} which owns the Record.
23351 * Rejects all changes made to the Record since either creation, or the last commit operation.
23352 * Modified fields are reverted to their original values.
23354 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23355 * of reject operations.
23357 reject : function(){
23358 var m = this.modified;
23360 if(typeof m[n] != "function"){
23361 this.data[n] = m[n];
23364 this.dirty = false;
23365 delete this.modified;
23366 this.editing = false;
23368 this.store.afterReject(this);
23373 * Usually called by the {@link Roo.data.Store} which owns the Record.
23374 * Commits all changes made to the Record since either creation, or the last commit operation.
23376 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23377 * of commit operations.
23379 commit : function(){
23380 this.dirty = false;
23381 delete this.modified;
23382 this.editing = false;
23384 this.store.afterCommit(this);
23389 hasError : function(){
23390 return this.error != null;
23394 clearError : function(){
23399 * Creates a copy of this record.
23400 * @param {String} id (optional) A new record id if you don't want to use this record's id
23403 copy : function(newId) {
23404 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
23408 * Ext JS Library 1.1.1
23409 * Copyright(c) 2006-2007, Ext JS, LLC.
23411 * Originally Released Under LGPL - original licence link has changed is not relivant.
23414 * <script type="text/javascript">
23420 * @class Roo.data.Store
23421 * @extends Roo.util.Observable
23422 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
23423 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
23425 * 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
23426 * has no knowledge of the format of the data returned by the Proxy.<br>
23428 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
23429 * instances from the data object. These records are cached and made available through accessor functions.
23431 * Creates a new Store.
23432 * @param {Object} config A config object containing the objects needed for the Store to access data,
23433 * and read the data into Records.
23435 Roo.data.Store = function(config){
23436 this.data = new Roo.util.MixedCollection(false);
23437 this.data.getKey = function(o){
23440 this.baseParams = {};
23442 this.paramNames = {
23447 "multisort" : "_multisort"
23450 if(config && config.data){
23451 this.inlineData = config.data;
23452 delete config.data;
23455 Roo.apply(this, config);
23457 if(this.reader){ // reader passed
23458 this.reader = Roo.factory(this.reader, Roo.data);
23459 this.reader.xmodule = this.xmodule || false;
23460 if(!this.recordType){
23461 this.recordType = this.reader.recordType;
23463 if(this.reader.onMetaChange){
23464 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
23468 if(this.recordType){
23469 this.fields = this.recordType.prototype.fields;
23471 this.modified = [];
23475 * @event datachanged
23476 * Fires when the data cache has changed, and a widget which is using this Store
23477 * as a Record cache should refresh its view.
23478 * @param {Store} this
23480 datachanged : true,
23482 * @event metachange
23483 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
23484 * @param {Store} this
23485 * @param {Object} meta The JSON metadata
23490 * Fires when Records have been added to the Store
23491 * @param {Store} this
23492 * @param {Roo.data.Record[]} records The array of Records added
23493 * @param {Number} index The index at which the record(s) were added
23498 * Fires when a Record has been removed from the Store
23499 * @param {Store} this
23500 * @param {Roo.data.Record} record The Record that was removed
23501 * @param {Number} index The index at which the record was removed
23506 * Fires when a Record has been updated
23507 * @param {Store} this
23508 * @param {Roo.data.Record} record The Record that was updated
23509 * @param {String} operation The update operation being performed. Value may be one of:
23511 Roo.data.Record.EDIT
23512 Roo.data.Record.REJECT
23513 Roo.data.Record.COMMIT
23519 * Fires when the data cache has been cleared.
23520 * @param {Store} this
23524 * @event beforeload
23525 * Fires before a request is made for a new data object. If the beforeload handler returns false
23526 * the load action will be canceled.
23527 * @param {Store} this
23528 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23532 * @event beforeloadadd
23533 * Fires after a new set of Records has been loaded.
23534 * @param {Store} this
23535 * @param {Roo.data.Record[]} records The Records that were loaded
23536 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23538 beforeloadadd : true,
23541 * Fires after a new set of Records has been loaded, before they are added to the store.
23542 * @param {Store} this
23543 * @param {Roo.data.Record[]} records The Records that were loaded
23544 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23545 * @params {Object} return from reader
23549 * @event loadexception
23550 * Fires if an exception occurs in the Proxy during loading.
23551 * Called with the signature of the Proxy's "loadexception" event.
23552 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
23555 * @param {Object} return from JsonData.reader() - success, totalRecords, records
23556 * @param {Object} load options
23557 * @param {Object} jsonData from your request (normally this contains the Exception)
23559 loadexception : true
23563 this.proxy = Roo.factory(this.proxy, Roo.data);
23564 this.proxy.xmodule = this.xmodule || false;
23565 this.relayEvents(this.proxy, ["loadexception"]);
23567 this.sortToggle = {};
23568 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
23570 Roo.data.Store.superclass.constructor.call(this);
23572 if(this.inlineData){
23573 this.loadData(this.inlineData);
23574 delete this.inlineData;
23578 Roo.extend(Roo.data.Store, Roo.util.Observable, {
23580 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
23581 * without a remote query - used by combo/forms at present.
23585 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
23588 * @cfg {Array} data Inline data to be loaded when the store is initialized.
23591 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
23592 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
23595 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
23596 * on any HTTP request
23599 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
23602 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
23606 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
23607 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
23609 remoteSort : false,
23612 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
23613 * loaded or when a record is removed. (defaults to false).
23615 pruneModifiedRecords : false,
23618 lastOptions : null,
23621 * Add Records to the Store and fires the add event.
23622 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23624 add : function(records){
23625 records = [].concat(records);
23626 for(var i = 0, len = records.length; i < len; i++){
23627 records[i].join(this);
23629 var index = this.data.length;
23630 this.data.addAll(records);
23631 this.fireEvent("add", this, records, index);
23635 * Remove a Record from the Store and fires the remove event.
23636 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23638 remove : function(record){
23639 var index = this.data.indexOf(record);
23640 this.data.removeAt(index);
23642 if(this.pruneModifiedRecords){
23643 this.modified.remove(record);
23645 this.fireEvent("remove", this, record, index);
23649 * Remove all Records from the Store and fires the clear event.
23651 removeAll : function(){
23653 if(this.pruneModifiedRecords){
23654 this.modified = [];
23656 this.fireEvent("clear", this);
23660 * Inserts Records to the Store at the given index and fires the add event.
23661 * @param {Number} index The start index at which to insert the passed Records.
23662 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23664 insert : function(index, records){
23665 records = [].concat(records);
23666 for(var i = 0, len = records.length; i < len; i++){
23667 this.data.insert(index, records[i]);
23668 records[i].join(this);
23670 this.fireEvent("add", this, records, index);
23674 * Get the index within the cache of the passed Record.
23675 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23676 * @return {Number} The index of the passed Record. Returns -1 if not found.
23678 indexOf : function(record){
23679 return this.data.indexOf(record);
23683 * Get the index within the cache of the Record with the passed id.
23684 * @param {String} id The id of the Record to find.
23685 * @return {Number} The index of the Record. Returns -1 if not found.
23687 indexOfId : function(id){
23688 return this.data.indexOfKey(id);
23692 * Get the Record with the specified id.
23693 * @param {String} id The id of the Record to find.
23694 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23696 getById : function(id){
23697 return this.data.key(id);
23701 * Get the Record at the specified index.
23702 * @param {Number} index The index of the Record to find.
23703 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23705 getAt : function(index){
23706 return this.data.itemAt(index);
23710 * Returns a range of Records between specified indices.
23711 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23712 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23713 * @return {Roo.data.Record[]} An array of Records
23715 getRange : function(start, end){
23716 return this.data.getRange(start, end);
23720 storeOptions : function(o){
23721 o = Roo.apply({}, o);
23724 this.lastOptions = o;
23728 * Loads the Record cache from the configured Proxy using the configured Reader.
23730 * If using remote paging, then the first load call must specify the <em>start</em>
23731 * and <em>limit</em> properties in the options.params property to establish the initial
23732 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23734 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23735 * and this call will return before the new data has been loaded. Perform any post-processing
23736 * in a callback function, or in a "load" event handler.</strong>
23738 * @param {Object} options An object containing properties which control loading options:<ul>
23739 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23740 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23741 * passed the following arguments:<ul>
23742 * <li>r : Roo.data.Record[]</li>
23743 * <li>options: Options object from the load call</li>
23744 * <li>success: Boolean success indicator</li></ul></li>
23745 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23746 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23749 load : function(options){
23750 options = options || {};
23751 if(this.fireEvent("beforeload", this, options) !== false){
23752 this.storeOptions(options);
23753 var p = Roo.apply(options.params || {}, this.baseParams);
23754 // if meta was not loaded from remote source.. try requesting it.
23755 if (!this.reader.metaFromRemote) {
23756 p._requestMeta = 1;
23758 if(this.sortInfo && this.remoteSort){
23759 var pn = this.paramNames;
23760 p[pn["sort"]] = this.sortInfo.field;
23761 p[pn["dir"]] = this.sortInfo.direction;
23763 if (this.multiSort) {
23764 var pn = this.paramNames;
23765 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23768 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23773 * Reloads the Record cache from the configured Proxy using the configured Reader and
23774 * the options from the last load operation performed.
23775 * @param {Object} options (optional) An object containing properties which may override the options
23776 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23777 * the most recently used options are reused).
23779 reload : function(options){
23780 this.load(Roo.applyIf(options||{}, this.lastOptions));
23784 // Called as a callback by the Reader during a load operation.
23785 loadRecords : function(o, options, success){
23786 if(!o || success === false){
23787 if(success !== false){
23788 this.fireEvent("load", this, [], options, o);
23790 if(options.callback){
23791 options.callback.call(options.scope || this, [], options, false);
23795 // if data returned failure - throw an exception.
23796 if (o.success === false) {
23797 // show a message if no listener is registered.
23798 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23799 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23801 // loadmask wil be hooked into this..
23802 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23805 var r = o.records, t = o.totalRecords || r.length;
23807 this.fireEvent("beforeloadadd", this, r, options, o);
23809 if(!options || options.add !== true){
23810 if(this.pruneModifiedRecords){
23811 this.modified = [];
23813 for(var i = 0, len = r.length; i < len; i++){
23817 this.data = this.snapshot;
23818 delete this.snapshot;
23821 this.data.addAll(r);
23822 this.totalLength = t;
23824 this.fireEvent("datachanged", this);
23826 this.totalLength = Math.max(t, this.data.length+r.length);
23830 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23832 var e = new Roo.data.Record({});
23834 e.set(this.parent.displayField, this.parent.emptyTitle);
23835 e.set(this.parent.valueField, '');
23840 this.fireEvent("load", this, r, options, o);
23841 if(options.callback){
23842 options.callback.call(options.scope || this, r, options, true);
23848 * Loads data from a passed data block. A Reader which understands the format of the data
23849 * must have been configured in the constructor.
23850 * @param {Object} data The data block from which to read the Records. The format of the data expected
23851 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23852 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23854 loadData : function(o, append){
23855 var r = this.reader.readRecords(o);
23856 this.loadRecords(r, {add: append}, true);
23860 * using 'cn' the nested child reader read the child array into it's child stores.
23861 * @param {Object} rec The record with a 'children array
23863 loadDataFromChildren : function(rec)
23865 this.loadData(this.reader.toLoadData(rec));
23870 * Gets the number of cached records.
23872 * <em>If using paging, this may not be the total size of the dataset. If the data object
23873 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23874 * the data set size</em>
23876 getCount : function(){
23877 return this.data.length || 0;
23881 * Gets the total number of records in the dataset as returned by the server.
23883 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23884 * the dataset size</em>
23886 getTotalCount : function(){
23887 return this.totalLength || 0;
23891 * Returns the sort state of the Store as an object with two properties:
23893 field {String} The name of the field by which the Records are sorted
23894 direction {String} The sort order, "ASC" or "DESC"
23897 getSortState : function(){
23898 return this.sortInfo;
23902 applySort : function(){
23903 if(this.sortInfo && !this.remoteSort){
23904 var s = this.sortInfo, f = s.field;
23905 var st = this.fields.get(f).sortType;
23906 var fn = function(r1, r2){
23907 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23908 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23910 this.data.sort(s.direction, fn);
23911 if(this.snapshot && this.snapshot != this.data){
23912 this.snapshot.sort(s.direction, fn);
23918 * Sets the default sort column and order to be used by the next load operation.
23919 * @param {String} fieldName The name of the field to sort by.
23920 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23922 setDefaultSort : function(field, dir){
23923 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23927 * Sort the Records.
23928 * If remote sorting is used, the sort is performed on the server, and the cache is
23929 * reloaded. If local sorting is used, the cache is sorted internally.
23930 * @param {String} fieldName The name of the field to sort by.
23931 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23933 sort : function(fieldName, dir){
23934 var f = this.fields.get(fieldName);
23936 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23938 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23939 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23944 this.sortToggle[f.name] = dir;
23945 this.sortInfo = {field: f.name, direction: dir};
23946 if(!this.remoteSort){
23948 this.fireEvent("datachanged", this);
23950 this.load(this.lastOptions);
23955 * Calls the specified function for each of the Records in the cache.
23956 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23957 * Returning <em>false</em> aborts and exits the iteration.
23958 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23960 each : function(fn, scope){
23961 this.data.each(fn, scope);
23965 * Gets all records modified since the last commit. Modified records are persisted across load operations
23966 * (e.g., during paging).
23967 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23969 getModifiedRecords : function(){
23970 return this.modified;
23974 createFilterFn : function(property, value, anyMatch){
23975 if(!value.exec){ // not a regex
23976 value = String(value);
23977 if(value.length == 0){
23980 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23982 return function(r){
23983 return value.test(r.data[property]);
23988 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23989 * @param {String} property A field on your records
23990 * @param {Number} start The record index to start at (defaults to 0)
23991 * @param {Number} end The last record index to include (defaults to length - 1)
23992 * @return {Number} The sum
23994 sum : function(property, start, end){
23995 var rs = this.data.items, v = 0;
23996 start = start || 0;
23997 end = (end || end === 0) ? end : rs.length-1;
23999 for(var i = start; i <= end; i++){
24000 v += (rs[i].data[property] || 0);
24006 * Filter the records by a specified property.
24007 * @param {String} field A field on your records
24008 * @param {String/RegExp} value Either a string that the field
24009 * should start with or a RegExp to test against the field
24010 * @param {Boolean} anyMatch True to match any part not just the beginning
24012 filter : function(property, value, anyMatch){
24013 var fn = this.createFilterFn(property, value, anyMatch);
24014 return fn ? this.filterBy(fn) : this.clearFilter();
24018 * Filter by a function. The specified function will be called with each
24019 * record in this data source. If the function returns true the record is included,
24020 * otherwise it is filtered.
24021 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24022 * @param {Object} scope (optional) The scope of the function (defaults to this)
24024 filterBy : function(fn, scope){
24025 this.snapshot = this.snapshot || this.data;
24026 this.data = this.queryBy(fn, scope||this);
24027 this.fireEvent("datachanged", this);
24031 * Query the records by a specified property.
24032 * @param {String} field A field on your records
24033 * @param {String/RegExp} value Either a string that the field
24034 * should start with or a RegExp to test against the field
24035 * @param {Boolean} anyMatch True to match any part not just the beginning
24036 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24038 query : function(property, value, anyMatch){
24039 var fn = this.createFilterFn(property, value, anyMatch);
24040 return fn ? this.queryBy(fn) : this.data.clone();
24044 * Query by a function. The specified function will be called with each
24045 * record in this data source. If the function returns true the record is included
24047 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24048 * @param {Object} scope (optional) The scope of the function (defaults to this)
24049 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24051 queryBy : function(fn, scope){
24052 var data = this.snapshot || this.data;
24053 return data.filterBy(fn, scope||this);
24057 * Collects unique values for a particular dataIndex from this store.
24058 * @param {String} dataIndex The property to collect
24059 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24060 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24061 * @return {Array} An array of the unique values
24063 collect : function(dataIndex, allowNull, bypassFilter){
24064 var d = (bypassFilter === true && this.snapshot) ?
24065 this.snapshot.items : this.data.items;
24066 var v, sv, r = [], l = {};
24067 for(var i = 0, len = d.length; i < len; i++){
24068 v = d[i].data[dataIndex];
24070 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24079 * Revert to a view of the Record cache with no filtering applied.
24080 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24082 clearFilter : function(suppressEvent){
24083 if(this.snapshot && this.snapshot != this.data){
24084 this.data = this.snapshot;
24085 delete this.snapshot;
24086 if(suppressEvent !== true){
24087 this.fireEvent("datachanged", this);
24093 afterEdit : function(record){
24094 if(this.modified.indexOf(record) == -1){
24095 this.modified.push(record);
24097 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24101 afterReject : function(record){
24102 this.modified.remove(record);
24103 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24107 afterCommit : function(record){
24108 this.modified.remove(record);
24109 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24113 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24114 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24116 commitChanges : function(){
24117 var m = this.modified.slice(0);
24118 this.modified = [];
24119 for(var i = 0, len = m.length; i < len; i++){
24125 * Cancel outstanding changes on all changed records.
24127 rejectChanges : function(){
24128 var m = this.modified.slice(0);
24129 this.modified = [];
24130 for(var i = 0, len = m.length; i < len; i++){
24135 onMetaChange : function(meta, rtype, o){
24136 this.recordType = rtype;
24137 this.fields = rtype.prototype.fields;
24138 delete this.snapshot;
24139 this.sortInfo = meta.sortInfo || this.sortInfo;
24140 this.modified = [];
24141 this.fireEvent('metachange', this, this.reader.meta);
24144 moveIndex : function(data, type)
24146 var index = this.indexOf(data);
24148 var newIndex = index + type;
24152 this.insert(newIndex, data);
24157 * Ext JS Library 1.1.1
24158 * Copyright(c) 2006-2007, Ext JS, LLC.
24160 * Originally Released Under LGPL - original licence link has changed is not relivant.
24163 * <script type="text/javascript">
24167 * @class Roo.data.SimpleStore
24168 * @extends Roo.data.Store
24169 * Small helper class to make creating Stores from Array data easier.
24170 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24171 * @cfg {Array} fields An array of field definition objects, or field name strings.
24172 * @cfg {Object} an existing reader (eg. copied from another store)
24173 * @cfg {Array} data The multi-dimensional array of data
24175 * @param {Object} config
24177 Roo.data.SimpleStore = function(config)
24179 Roo.data.SimpleStore.superclass.constructor.call(this, {
24181 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24184 Roo.data.Record.create(config.fields)
24186 proxy : new Roo.data.MemoryProxy(config.data)
24190 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24192 * Ext JS Library 1.1.1
24193 * Copyright(c) 2006-2007, Ext JS, LLC.
24195 * Originally Released Under LGPL - original licence link has changed is not relivant.
24198 * <script type="text/javascript">
24203 * @extends Roo.data.Store
24204 * @class Roo.data.JsonStore
24205 * Small helper class to make creating Stores for JSON data easier. <br/>
24207 var store = new Roo.data.JsonStore({
24208 url: 'get-images.php',
24210 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24213 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24214 * JsonReader and HttpProxy (unless inline data is provided).</b>
24215 * @cfg {Array} fields An array of field definition objects, or field name strings.
24217 * @param {Object} config
24219 Roo.data.JsonStore = function(c){
24220 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24221 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24222 reader: new Roo.data.JsonReader(c, c.fields)
24225 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
24227 * Ext JS Library 1.1.1
24228 * Copyright(c) 2006-2007, Ext JS, LLC.
24230 * Originally Released Under LGPL - original licence link has changed is not relivant.
24233 * <script type="text/javascript">
24237 Roo.data.Field = function(config){
24238 if(typeof config == "string"){
24239 config = {name: config};
24241 Roo.apply(this, config);
24244 this.type = "auto";
24247 var st = Roo.data.SortTypes;
24248 // named sortTypes are supported, here we look them up
24249 if(typeof this.sortType == "string"){
24250 this.sortType = st[this.sortType];
24253 // set default sortType for strings and dates
24254 if(!this.sortType){
24257 this.sortType = st.asUCString;
24260 this.sortType = st.asDate;
24263 this.sortType = st.none;
24268 var stripRe = /[\$,%]/g;
24270 // prebuilt conversion function for this field, instead of
24271 // switching every time we're reading a value
24273 var cv, dateFormat = this.dateFormat;
24278 cv = function(v){ return v; };
24281 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24285 return v !== undefined && v !== null && v !== '' ?
24286 parseInt(String(v).replace(stripRe, ""), 10) : '';
24291 return v !== undefined && v !== null && v !== '' ?
24292 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24297 cv = function(v){ return v === true || v === "true" || v == 1; };
24304 if(v instanceof Date){
24308 if(dateFormat == "timestamp"){
24309 return new Date(v*1000);
24311 return Date.parseDate(v, dateFormat);
24313 var parsed = Date.parse(v);
24314 return parsed ? new Date(parsed) : null;
24323 Roo.data.Field.prototype = {
24331 * Ext JS Library 1.1.1
24332 * Copyright(c) 2006-2007, Ext JS, LLC.
24334 * Originally Released Under LGPL - original licence link has changed is not relivant.
24337 * <script type="text/javascript">
24340 // Base class for reading structured data from a data source. This class is intended to be
24341 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24344 * @class Roo.data.DataReader
24345 * Base class for reading structured data from a data source. This class is intended to be
24346 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24349 Roo.data.DataReader = function(meta, recordType){
24353 this.recordType = recordType instanceof Array ?
24354 Roo.data.Record.create(recordType) : recordType;
24357 Roo.data.DataReader.prototype = {
24360 readerType : 'Data',
24362 * Create an empty record
24363 * @param {Object} data (optional) - overlay some values
24364 * @return {Roo.data.Record} record created.
24366 newRow : function(d) {
24368 this.recordType.prototype.fields.each(function(c) {
24370 case 'int' : da[c.name] = 0; break;
24371 case 'date' : da[c.name] = new Date(); break;
24372 case 'float' : da[c.name] = 0.0; break;
24373 case 'boolean' : da[c.name] = false; break;
24374 default : da[c.name] = ""; break;
24378 return new this.recordType(Roo.apply(da, d));
24384 * Ext JS Library 1.1.1
24385 * Copyright(c) 2006-2007, Ext JS, LLC.
24387 * Originally Released Under LGPL - original licence link has changed is not relivant.
24390 * <script type="text/javascript">
24394 * @class Roo.data.DataProxy
24395 * @extends Roo.data.Observable
24396 * This class is an abstract base class for implementations which provide retrieval of
24397 * unformatted data objects.<br>
24399 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24400 * (of the appropriate type which knows how to parse the data object) to provide a block of
24401 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24403 * Custom implementations must implement the load method as described in
24404 * {@link Roo.data.HttpProxy#load}.
24406 Roo.data.DataProxy = function(){
24409 * @event beforeload
24410 * Fires before a network request is made to retrieve a data object.
24411 * @param {Object} This DataProxy object.
24412 * @param {Object} params The params parameter to the load function.
24417 * Fires before the load method's callback is called.
24418 * @param {Object} This DataProxy object.
24419 * @param {Object} o The data object.
24420 * @param {Object} arg The callback argument object passed to the load function.
24424 * @event loadexception
24425 * Fires if an Exception occurs during data retrieval.
24426 * @param {Object} This DataProxy object.
24427 * @param {Object} o The data object.
24428 * @param {Object} arg The callback argument object passed to the load function.
24429 * @param {Object} e The Exception.
24431 loadexception : true
24433 Roo.data.DataProxy.superclass.constructor.call(this);
24436 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24439 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24443 * Ext JS Library 1.1.1
24444 * Copyright(c) 2006-2007, Ext JS, LLC.
24446 * Originally Released Under LGPL - original licence link has changed is not relivant.
24449 * <script type="text/javascript">
24452 * @class Roo.data.MemoryProxy
24453 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24454 * to the Reader when its load method is called.
24456 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24458 Roo.data.MemoryProxy = function(data){
24462 Roo.data.MemoryProxy.superclass.constructor.call(this);
24466 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24469 * Load data from the requested source (in this case an in-memory
24470 * data object passed to the constructor), read the data object into
24471 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24472 * process that block using the passed callback.
24473 * @param {Object} params This parameter is not used by the MemoryProxy class.
24474 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24475 * object into a block of Roo.data.Records.
24476 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24477 * The function must be passed <ul>
24478 * <li>The Record block object</li>
24479 * <li>The "arg" argument from the load function</li>
24480 * <li>A boolean success indicator</li>
24482 * @param {Object} scope The scope in which to call the callback
24483 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24485 load : function(params, reader, callback, scope, arg){
24486 params = params || {};
24489 result = reader.readRecords(params.data ? params.data :this.data);
24491 this.fireEvent("loadexception", this, arg, null, e);
24492 callback.call(scope, null, arg, false);
24495 callback.call(scope, result, arg, true);
24499 update : function(params, records){
24504 * Ext JS Library 1.1.1
24505 * Copyright(c) 2006-2007, Ext JS, LLC.
24507 * Originally Released Under LGPL - original licence link has changed is not relivant.
24510 * <script type="text/javascript">
24513 * @class Roo.data.HttpProxy
24514 * @extends Roo.data.DataProxy
24515 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24516 * configured to reference a certain URL.<br><br>
24518 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24519 * from which the running page was served.<br><br>
24521 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24523 * Be aware that to enable the browser to parse an XML document, the server must set
24524 * the Content-Type header in the HTTP response to "text/xml".
24526 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24527 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24528 * will be used to make the request.
24530 Roo.data.HttpProxy = function(conn){
24531 Roo.data.HttpProxy.superclass.constructor.call(this);
24532 // is conn a conn config or a real conn?
24534 this.useAjax = !conn || !conn.events;
24538 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24539 // thse are take from connection...
24542 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24545 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24546 * extra parameters to each request made by this object. (defaults to undefined)
24549 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24550 * to each request made by this object. (defaults to undefined)
24553 * @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)
24556 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24559 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24565 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24569 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24570 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24571 * a finer-grained basis than the DataProxy events.
24573 getConnection : function(){
24574 return this.useAjax ? Roo.Ajax : this.conn;
24578 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24579 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24580 * process that block using the passed callback.
24581 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24582 * for the request to the remote server.
24583 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24584 * object into a block of Roo.data.Records.
24585 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24586 * The function must be passed <ul>
24587 * <li>The Record block object</li>
24588 * <li>The "arg" argument from the load function</li>
24589 * <li>A boolean success indicator</li>
24591 * @param {Object} scope The scope in which to call the callback
24592 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24594 load : function(params, reader, callback, scope, arg){
24595 if(this.fireEvent("beforeload", this, params) !== false){
24597 params : params || {},
24599 callback : callback,
24604 callback : this.loadResponse,
24608 Roo.applyIf(o, this.conn);
24609 if(this.activeRequest){
24610 Roo.Ajax.abort(this.activeRequest);
24612 this.activeRequest = Roo.Ajax.request(o);
24614 this.conn.request(o);
24617 callback.call(scope||this, null, arg, false);
24622 loadResponse : function(o, success, response){
24623 delete this.activeRequest;
24625 this.fireEvent("loadexception", this, o, response);
24626 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24631 result = o.reader.read(response);
24633 this.fireEvent("loadexception", this, o, response, e);
24634 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24638 this.fireEvent("load", this, o, o.request.arg);
24639 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24643 update : function(dataSet){
24648 updateResponse : function(dataSet){
24653 * Ext JS Library 1.1.1
24654 * Copyright(c) 2006-2007, Ext JS, LLC.
24656 * Originally Released Under LGPL - original licence link has changed is not relivant.
24659 * <script type="text/javascript">
24663 * @class Roo.data.ScriptTagProxy
24664 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24665 * other than the originating domain of the running page.<br><br>
24667 * <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
24668 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24670 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24671 * source code that is used as the source inside a <script> tag.<br><br>
24673 * In order for the browser to process the returned data, the server must wrap the data object
24674 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24675 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24676 * depending on whether the callback name was passed:
24679 boolean scriptTag = false;
24680 String cb = request.getParameter("callback");
24683 response.setContentType("text/javascript");
24685 response.setContentType("application/x-json");
24687 Writer out = response.getWriter();
24689 out.write(cb + "(");
24691 out.print(dataBlock.toJsonString());
24698 * @param {Object} config A configuration object.
24700 Roo.data.ScriptTagProxy = function(config){
24701 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24702 Roo.apply(this, config);
24703 this.head = document.getElementsByTagName("head")[0];
24706 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24708 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24710 * @cfg {String} url The URL from which to request the data object.
24713 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24717 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24718 * the server the name of the callback function set up by the load call to process the returned data object.
24719 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24720 * javascript output which calls this named function passing the data object as its only parameter.
24722 callbackParam : "callback",
24724 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24725 * name to the request.
24730 * Load data from the configured URL, read the data object into
24731 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24732 * process that block using the passed callback.
24733 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24734 * for the request to the remote server.
24735 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24736 * object into a block of Roo.data.Records.
24737 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24738 * The function must be passed <ul>
24739 * <li>The Record block object</li>
24740 * <li>The "arg" argument from the load function</li>
24741 * <li>A boolean success indicator</li>
24743 * @param {Object} scope The scope in which to call the callback
24744 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24746 load : function(params, reader, callback, scope, arg){
24747 if(this.fireEvent("beforeload", this, params) !== false){
24749 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24751 var url = this.url;
24752 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24754 url += "&_dc=" + (new Date().getTime());
24756 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24759 cb : "stcCallback"+transId,
24760 scriptId : "stcScript"+transId,
24764 callback : callback,
24770 window[trans.cb] = function(o){
24771 conn.handleResponse(o, trans);
24774 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24776 if(this.autoAbort !== false){
24780 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24782 var script = document.createElement("script");
24783 script.setAttribute("src", url);
24784 script.setAttribute("type", "text/javascript");
24785 script.setAttribute("id", trans.scriptId);
24786 this.head.appendChild(script);
24788 this.trans = trans;
24790 callback.call(scope||this, null, arg, false);
24795 isLoading : function(){
24796 return this.trans ? true : false;
24800 * Abort the current server request.
24802 abort : function(){
24803 if(this.isLoading()){
24804 this.destroyTrans(this.trans);
24809 destroyTrans : function(trans, isLoaded){
24810 this.head.removeChild(document.getElementById(trans.scriptId));
24811 clearTimeout(trans.timeoutId);
24813 window[trans.cb] = undefined;
24815 delete window[trans.cb];
24818 // if hasn't been loaded, wait for load to remove it to prevent script error
24819 window[trans.cb] = function(){
24820 window[trans.cb] = undefined;
24822 delete window[trans.cb];
24829 handleResponse : function(o, trans){
24830 this.trans = false;
24831 this.destroyTrans(trans, true);
24834 result = trans.reader.readRecords(o);
24836 this.fireEvent("loadexception", this, o, trans.arg, e);
24837 trans.callback.call(trans.scope||window, null, trans.arg, false);
24840 this.fireEvent("load", this, o, trans.arg);
24841 trans.callback.call(trans.scope||window, result, trans.arg, true);
24845 handleFailure : function(trans){
24846 this.trans = false;
24847 this.destroyTrans(trans, false);
24848 this.fireEvent("loadexception", this, null, trans.arg);
24849 trans.callback.call(trans.scope||window, null, trans.arg, false);
24853 * Ext JS Library 1.1.1
24854 * Copyright(c) 2006-2007, Ext JS, LLC.
24856 * Originally Released Under LGPL - original licence link has changed is not relivant.
24859 * <script type="text/javascript">
24863 * @class Roo.data.JsonReader
24864 * @extends Roo.data.DataReader
24865 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24866 * based on mappings in a provided Roo.data.Record constructor.
24868 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24869 * in the reply previously.
24874 var RecordDef = Roo.data.Record.create([
24875 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24876 {name: 'occupation'} // This field will use "occupation" as the mapping.
24878 var myReader = new Roo.data.JsonReader({
24879 totalProperty: "results", // The property which contains the total dataset size (optional)
24880 root: "rows", // The property which contains an Array of row objects
24881 id: "id" // The property within each row object that provides an ID for the record (optional)
24885 * This would consume a JSON file like this:
24887 { 'results': 2, 'rows': [
24888 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24889 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24892 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24893 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24894 * paged from the remote server.
24895 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24896 * @cfg {String} root name of the property which contains the Array of row objects.
24897 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24898 * @cfg {Array} fields Array of field definition objects
24900 * Create a new JsonReader
24901 * @param {Object} meta Metadata configuration options
24902 * @param {Object} recordType Either an Array of field definition objects,
24903 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24905 Roo.data.JsonReader = function(meta, recordType){
24908 // set some defaults:
24909 Roo.applyIf(meta, {
24910 totalProperty: 'total',
24911 successProperty : 'success',
24916 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24918 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24920 readerType : 'Json',
24923 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24924 * Used by Store query builder to append _requestMeta to params.
24927 metaFromRemote : false,
24929 * This method is only used by a DataProxy which has retrieved data from a remote server.
24930 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24931 * @return {Object} data A data block which is used by an Roo.data.Store object as
24932 * a cache of Roo.data.Records.
24934 read : function(response){
24935 var json = response.responseText;
24937 var o = /* eval:var:o */ eval("("+json+")");
24939 throw {message: "JsonReader.read: Json object not found"};
24945 this.metaFromRemote = true;
24946 this.meta = o.metaData;
24947 this.recordType = Roo.data.Record.create(o.metaData.fields);
24948 this.onMetaChange(this.meta, this.recordType, o);
24950 return this.readRecords(o);
24953 // private function a store will implement
24954 onMetaChange : function(meta, recordType, o){
24961 simpleAccess: function(obj, subsc) {
24968 getJsonAccessor: function(){
24970 return function(expr) {
24972 return(re.test(expr))
24973 ? new Function("obj", "return obj." + expr)
24978 return Roo.emptyFn;
24983 * Create a data block containing Roo.data.Records from an XML document.
24984 * @param {Object} o An object which contains an Array of row objects in the property specified
24985 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24986 * which contains the total size of the dataset.
24987 * @return {Object} data A data block which is used by an Roo.data.Store object as
24988 * a cache of Roo.data.Records.
24990 readRecords : function(o){
24992 * After any data loads, the raw JSON data is available for further custom processing.
24996 var s = this.meta, Record = this.recordType,
24997 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24999 // Generate extraction functions for the totalProperty, the root, the id, and for each field
25001 if(s.totalProperty) {
25002 this.getTotal = this.getJsonAccessor(s.totalProperty);
25004 if(s.successProperty) {
25005 this.getSuccess = this.getJsonAccessor(s.successProperty);
25007 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
25009 var g = this.getJsonAccessor(s.id);
25010 this.getId = function(rec) {
25012 return (r === undefined || r === "") ? null : r;
25015 this.getId = function(){return null;};
25018 for(var jj = 0; jj < fl; jj++){
25020 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
25021 this.ef[jj] = this.getJsonAccessor(map);
25025 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
25026 if(s.totalProperty){
25027 var vt = parseInt(this.getTotal(o), 10);
25032 if(s.successProperty){
25033 var vs = this.getSuccess(o);
25034 if(vs === false || vs === 'false'){
25039 for(var i = 0; i < c; i++){
25042 var id = this.getId(n);
25043 for(var j = 0; j < fl; j++){
25045 var v = this.ef[j](n);
25047 Roo.log('missing convert for ' + f.name);
25051 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25053 var record = new Record(values, id);
25055 records[i] = record;
25061 totalRecords : totalRecords
25064 // used when loading children.. @see loadDataFromChildren
25065 toLoadData: function(rec)
25067 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25068 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25069 return { data : data, total : data.length };
25074 * Ext JS Library 1.1.1
25075 * Copyright(c) 2006-2007, Ext JS, LLC.
25077 * Originally Released Under LGPL - original licence link has changed is not relivant.
25080 * <script type="text/javascript">
25084 * @class Roo.data.XmlReader
25085 * @extends Roo.data.DataReader
25086 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25087 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25089 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25090 * header in the HTTP response must be set to "text/xml".</em>
25094 var RecordDef = Roo.data.Record.create([
25095 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25096 {name: 'occupation'} // This field will use "occupation" as the mapping.
25098 var myReader = new Roo.data.XmlReader({
25099 totalRecords: "results", // The element which contains the total dataset size (optional)
25100 record: "row", // The repeated element which contains row information
25101 id: "id" // The element within the row that provides an ID for the record (optional)
25105 * This would consume an XML file like this:
25109 <results>2</results>
25112 <name>Bill</name>
25113 <occupation>Gardener</occupation>
25117 <name>Ben</name>
25118 <occupation>Horticulturalist</occupation>
25122 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25123 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25124 * paged from the remote server.
25125 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25126 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25127 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25128 * a record identifier value.
25130 * Create a new XmlReader
25131 * @param {Object} meta Metadata configuration options
25132 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25133 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25134 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25136 Roo.data.XmlReader = function(meta, recordType){
25138 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25140 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25142 readerType : 'Xml',
25145 * This method is only used by a DataProxy which has retrieved data from a remote server.
25146 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25147 * to contain a method called 'responseXML' that returns an XML document object.
25148 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25149 * a cache of Roo.data.Records.
25151 read : function(response){
25152 var doc = response.responseXML;
25154 throw {message: "XmlReader.read: XML Document not available"};
25156 return this.readRecords(doc);
25160 * Create a data block containing Roo.data.Records from an XML document.
25161 * @param {Object} doc A parsed XML document.
25162 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25163 * a cache of Roo.data.Records.
25165 readRecords : function(doc){
25167 * After any data loads/reads, the raw XML Document is available for further custom processing.
25168 * @type XMLDocument
25170 this.xmlData = doc;
25171 var root = doc.documentElement || doc;
25172 var q = Roo.DomQuery;
25173 var recordType = this.recordType, fields = recordType.prototype.fields;
25174 var sid = this.meta.id;
25175 var totalRecords = 0, success = true;
25176 if(this.meta.totalRecords){
25177 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25180 if(this.meta.success){
25181 var sv = q.selectValue(this.meta.success, root, true);
25182 success = sv !== false && sv !== 'false';
25185 var ns = q.select(this.meta.record, root);
25186 for(var i = 0, len = ns.length; i < len; i++) {
25189 var id = sid ? q.selectValue(sid, n) : undefined;
25190 for(var j = 0, jlen = fields.length; j < jlen; j++){
25191 var f = fields.items[j];
25192 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25194 values[f.name] = v;
25196 var record = new recordType(values, id);
25198 records[records.length] = record;
25204 totalRecords : totalRecords || records.length
25209 * Ext JS Library 1.1.1
25210 * Copyright(c) 2006-2007, Ext JS, LLC.
25212 * Originally Released Under LGPL - original licence link has changed is not relivant.
25215 * <script type="text/javascript">
25219 * @class Roo.data.ArrayReader
25220 * @extends Roo.data.DataReader
25221 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25222 * Each element of that Array represents a row of data fields. The
25223 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25224 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25228 var RecordDef = Roo.data.Record.create([
25229 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25230 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25232 var myReader = new Roo.data.ArrayReader({
25233 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25237 * This would consume an Array like this:
25239 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25243 * Create a new JsonReader
25244 * @param {Object} meta Metadata configuration options.
25245 * @param {Object|Array} recordType Either an Array of field definition objects
25247 * @cfg {Array} fields Array of field definition objects
25248 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25249 * as specified to {@link Roo.data.Record#create},
25250 * or an {@link Roo.data.Record} object
25253 * created using {@link Roo.data.Record#create}.
25255 Roo.data.ArrayReader = function(meta, recordType)
25257 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25260 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25263 * Create a data block containing Roo.data.Records from an XML document.
25264 * @param {Object} o An Array of row objects which represents the dataset.
25265 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25266 * a cache of Roo.data.Records.
25268 readRecords : function(o)
25270 var sid = this.meta ? this.meta.id : null;
25271 var recordType = this.recordType, fields = recordType.prototype.fields;
25274 for(var i = 0; i < root.length; i++){
25277 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25278 for(var j = 0, jlen = fields.length; j < jlen; j++){
25279 var f = fields.items[j];
25280 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25281 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25283 values[f.name] = v;
25285 var record = new recordType(values, id);
25287 records[records.length] = record;
25291 totalRecords : records.length
25294 // used when loading children.. @see loadDataFromChildren
25295 toLoadData: function(rec)
25297 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25298 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25305 * Ext JS Library 1.1.1
25306 * Copyright(c) 2006-2007, Ext JS, LLC.
25308 * Originally Released Under LGPL - original licence link has changed is not relivant.
25311 * <script type="text/javascript">
25316 * @class Roo.data.Tree
25317 * @extends Roo.util.Observable
25318 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25319 * in the tree have most standard DOM functionality.
25321 * @param {Node} root (optional) The root node
25323 Roo.data.Tree = function(root){
25324 this.nodeHash = {};
25326 * The root node for this tree
25331 this.setRootNode(root);
25336 * Fires when a new child node is appended to a node in this tree.
25337 * @param {Tree} tree The owner tree
25338 * @param {Node} parent The parent node
25339 * @param {Node} node The newly appended node
25340 * @param {Number} index The index of the newly appended node
25345 * Fires when a child node is removed from a node in this tree.
25346 * @param {Tree} tree The owner tree
25347 * @param {Node} parent The parent node
25348 * @param {Node} node The child node removed
25353 * Fires when a node is moved to a new location in the tree
25354 * @param {Tree} tree The owner tree
25355 * @param {Node} node The node moved
25356 * @param {Node} oldParent The old parent of this node
25357 * @param {Node} newParent The new parent of this node
25358 * @param {Number} index The index it was moved to
25363 * Fires when a new child node is inserted in a node in this tree.
25364 * @param {Tree} tree The owner tree
25365 * @param {Node} parent The parent node
25366 * @param {Node} node The child node inserted
25367 * @param {Node} refNode The child node the node was inserted before
25371 * @event beforeappend
25372 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25373 * @param {Tree} tree The owner tree
25374 * @param {Node} parent The parent node
25375 * @param {Node} node The child node to be appended
25377 "beforeappend" : true,
25379 * @event beforeremove
25380 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25381 * @param {Tree} tree The owner tree
25382 * @param {Node} parent The parent node
25383 * @param {Node} node The child node to be removed
25385 "beforeremove" : true,
25387 * @event beforemove
25388 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25389 * @param {Tree} tree The owner tree
25390 * @param {Node} node The node being moved
25391 * @param {Node} oldParent The parent of the node
25392 * @param {Node} newParent The new parent the node is moving to
25393 * @param {Number} index The index it is being moved to
25395 "beforemove" : true,
25397 * @event beforeinsert
25398 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25399 * @param {Tree} tree The owner tree
25400 * @param {Node} parent The parent node
25401 * @param {Node} node The child node to be inserted
25402 * @param {Node} refNode The child node the node is being inserted before
25404 "beforeinsert" : true
25407 Roo.data.Tree.superclass.constructor.call(this);
25410 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25411 pathSeparator: "/",
25413 proxyNodeEvent : function(){
25414 return this.fireEvent.apply(this, arguments);
25418 * Returns the root node for this tree.
25421 getRootNode : function(){
25426 * Sets the root node for this tree.
25427 * @param {Node} node
25430 setRootNode : function(node){
25432 node.ownerTree = this;
25433 node.isRoot = true;
25434 this.registerNode(node);
25439 * Gets a node in this tree by its id.
25440 * @param {String} id
25443 getNodeById : function(id){
25444 return this.nodeHash[id];
25447 registerNode : function(node){
25448 this.nodeHash[node.id] = node;
25451 unregisterNode : function(node){
25452 delete this.nodeHash[node.id];
25455 toString : function(){
25456 return "[Tree"+(this.id?" "+this.id:"")+"]";
25461 * @class Roo.data.Node
25462 * @extends Roo.util.Observable
25463 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25464 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25466 * @param {Object} attributes The attributes/config for the node
25468 Roo.data.Node = function(attributes){
25470 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25473 this.attributes = attributes || {};
25474 this.leaf = this.attributes.leaf;
25476 * The node id. @type String
25478 this.id = this.attributes.id;
25480 this.id = Roo.id(null, "ynode-");
25481 this.attributes.id = this.id;
25486 * All child nodes of this node. @type Array
25488 this.childNodes = [];
25489 if(!this.childNodes.indexOf){ // indexOf is a must
25490 this.childNodes.indexOf = function(o){
25491 for(var i = 0, len = this.length; i < len; i++){
25500 * The parent node for this node. @type Node
25502 this.parentNode = null;
25504 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25506 this.firstChild = null;
25508 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25510 this.lastChild = null;
25512 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25514 this.previousSibling = null;
25516 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25518 this.nextSibling = null;
25523 * Fires when a new child node is appended
25524 * @param {Tree} tree The owner tree
25525 * @param {Node} this This node
25526 * @param {Node} node The newly appended node
25527 * @param {Number} index The index of the newly appended node
25532 * Fires when a child node is removed
25533 * @param {Tree} tree The owner tree
25534 * @param {Node} this This node
25535 * @param {Node} node The removed node
25540 * Fires when this node is moved to a new location in the tree
25541 * @param {Tree} tree The owner tree
25542 * @param {Node} this This node
25543 * @param {Node} oldParent The old parent of this node
25544 * @param {Node} newParent The new parent of this node
25545 * @param {Number} index The index it was moved to
25550 * Fires when a new child node is inserted.
25551 * @param {Tree} tree The owner tree
25552 * @param {Node} this This node
25553 * @param {Node} node The child node inserted
25554 * @param {Node} refNode The child node the node was inserted before
25558 * @event beforeappend
25559 * Fires before a new child is appended, return false to cancel the append.
25560 * @param {Tree} tree The owner tree
25561 * @param {Node} this This node
25562 * @param {Node} node The child node to be appended
25564 "beforeappend" : true,
25566 * @event beforeremove
25567 * Fires before a child is removed, return false to cancel the remove.
25568 * @param {Tree} tree The owner tree
25569 * @param {Node} this This node
25570 * @param {Node} node The child node to be removed
25572 "beforeremove" : true,
25574 * @event beforemove
25575 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25576 * @param {Tree} tree The owner tree
25577 * @param {Node} this This node
25578 * @param {Node} oldParent The parent of this node
25579 * @param {Node} newParent The new parent this node is moving to
25580 * @param {Number} index The index it is being moved to
25582 "beforemove" : true,
25584 * @event beforeinsert
25585 * Fires before a new child is inserted, return false to cancel the insert.
25586 * @param {Tree} tree The owner tree
25587 * @param {Node} this This node
25588 * @param {Node} node The child node to be inserted
25589 * @param {Node} refNode The child node the node is being inserted before
25591 "beforeinsert" : true
25593 this.listeners = this.attributes.listeners;
25594 Roo.data.Node.superclass.constructor.call(this);
25597 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25598 fireEvent : function(evtName){
25599 // first do standard event for this node
25600 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25603 // then bubble it up to the tree if the event wasn't cancelled
25604 var ot = this.getOwnerTree();
25606 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25614 * Returns true if this node is a leaf
25615 * @return {Boolean}
25617 isLeaf : function(){
25618 return this.leaf === true;
25622 setFirstChild : function(node){
25623 this.firstChild = node;
25627 setLastChild : function(node){
25628 this.lastChild = node;
25633 * Returns true if this node is the last child of its parent
25634 * @return {Boolean}
25636 isLast : function(){
25637 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25641 * Returns true if this node is the first child of its parent
25642 * @return {Boolean}
25644 isFirst : function(){
25645 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25648 hasChildNodes : function(){
25649 return !this.isLeaf() && this.childNodes.length > 0;
25653 * Insert node(s) as the last child node of this node.
25654 * @param {Node/Array} node The node or Array of nodes to append
25655 * @return {Node} The appended node if single append, or null if an array was passed
25657 appendChild : function(node){
25659 if(node instanceof Array){
25661 }else if(arguments.length > 1){
25665 // if passed an array or multiple args do them one by one
25667 for(var i = 0, len = multi.length; i < len; i++) {
25668 this.appendChild(multi[i]);
25671 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25674 var index = this.childNodes.length;
25675 var oldParent = node.parentNode;
25676 // it's a move, make sure we move it cleanly
25678 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25681 oldParent.removeChild(node);
25684 index = this.childNodes.length;
25686 this.setFirstChild(node);
25688 this.childNodes.push(node);
25689 node.parentNode = this;
25690 var ps = this.childNodes[index-1];
25692 node.previousSibling = ps;
25693 ps.nextSibling = node;
25695 node.previousSibling = null;
25697 node.nextSibling = null;
25698 this.setLastChild(node);
25699 node.setOwnerTree(this.getOwnerTree());
25700 this.fireEvent("append", this.ownerTree, this, node, index);
25701 if(this.ownerTree) {
25702 this.ownerTree.fireEvent("appendnode", this, node, index);
25705 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25712 * Removes a child node from this node.
25713 * @param {Node} node The node to remove
25714 * @return {Node} The removed node
25716 removeChild : function(node){
25717 var index = this.childNodes.indexOf(node);
25721 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25725 // remove it from childNodes collection
25726 this.childNodes.splice(index, 1);
25729 if(node.previousSibling){
25730 node.previousSibling.nextSibling = node.nextSibling;
25732 if(node.nextSibling){
25733 node.nextSibling.previousSibling = node.previousSibling;
25736 // update child refs
25737 if(this.firstChild == node){
25738 this.setFirstChild(node.nextSibling);
25740 if(this.lastChild == node){
25741 this.setLastChild(node.previousSibling);
25744 node.setOwnerTree(null);
25745 // clear any references from the node
25746 node.parentNode = null;
25747 node.previousSibling = null;
25748 node.nextSibling = null;
25749 this.fireEvent("remove", this.ownerTree, this, node);
25754 * Inserts the first node before the second node in this nodes childNodes collection.
25755 * @param {Node} node The node to insert
25756 * @param {Node} refNode The node to insert before (if null the node is appended)
25757 * @return {Node} The inserted node
25759 insertBefore : function(node, refNode){
25760 if(!refNode){ // like standard Dom, refNode can be null for append
25761 return this.appendChild(node);
25764 if(node == refNode){
25768 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25771 var index = this.childNodes.indexOf(refNode);
25772 var oldParent = node.parentNode;
25773 var refIndex = index;
25775 // when moving internally, indexes will change after remove
25776 if(oldParent == this && this.childNodes.indexOf(node) < index){
25780 // it's a move, make sure we move it cleanly
25782 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25785 oldParent.removeChild(node);
25788 this.setFirstChild(node);
25790 this.childNodes.splice(refIndex, 0, node);
25791 node.parentNode = this;
25792 var ps = this.childNodes[refIndex-1];
25794 node.previousSibling = ps;
25795 ps.nextSibling = node;
25797 node.previousSibling = null;
25799 node.nextSibling = refNode;
25800 refNode.previousSibling = node;
25801 node.setOwnerTree(this.getOwnerTree());
25802 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25804 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25810 * Returns the child node at the specified index.
25811 * @param {Number} index
25814 item : function(index){
25815 return this.childNodes[index];
25819 * Replaces one child node in this node with another.
25820 * @param {Node} newChild The replacement node
25821 * @param {Node} oldChild The node to replace
25822 * @return {Node} The replaced node
25824 replaceChild : function(newChild, oldChild){
25825 this.insertBefore(newChild, oldChild);
25826 this.removeChild(oldChild);
25831 * Returns the index of a child node
25832 * @param {Node} node
25833 * @return {Number} The index of the node or -1 if it was not found
25835 indexOf : function(child){
25836 return this.childNodes.indexOf(child);
25840 * Returns the tree this node is in.
25843 getOwnerTree : function(){
25844 // if it doesn't have one, look for one
25845 if(!this.ownerTree){
25849 this.ownerTree = p.ownerTree;
25855 return this.ownerTree;
25859 * Returns depth of this node (the root node has a depth of 0)
25862 getDepth : function(){
25865 while(p.parentNode){
25873 setOwnerTree : function(tree){
25874 // if it's move, we need to update everyone
25875 if(tree != this.ownerTree){
25876 if(this.ownerTree){
25877 this.ownerTree.unregisterNode(this);
25879 this.ownerTree = tree;
25880 var cs = this.childNodes;
25881 for(var i = 0, len = cs.length; i < len; i++) {
25882 cs[i].setOwnerTree(tree);
25885 tree.registerNode(this);
25891 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25892 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25893 * @return {String} The path
25895 getPath : function(attr){
25896 attr = attr || "id";
25897 var p = this.parentNode;
25898 var b = [this.attributes[attr]];
25900 b.unshift(p.attributes[attr]);
25903 var sep = this.getOwnerTree().pathSeparator;
25904 return sep + b.join(sep);
25908 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25909 * function call will be the scope provided or the current node. The arguments to the function
25910 * will be the args provided or the current node. If the function returns false at any point,
25911 * the bubble is stopped.
25912 * @param {Function} fn The function to call
25913 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25914 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25916 bubble : function(fn, scope, args){
25919 if(fn.call(scope || p, args || p) === false){
25927 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25928 * function call will be the scope provided or the current node. The arguments to the function
25929 * will be the args provided or the current node. If the function returns false at any point,
25930 * the cascade is stopped on that branch.
25931 * @param {Function} fn The function to call
25932 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25933 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25935 cascade : function(fn, scope, args){
25936 if(fn.call(scope || this, args || this) !== false){
25937 var cs = this.childNodes;
25938 for(var i = 0, len = cs.length; i < len; i++) {
25939 cs[i].cascade(fn, scope, args);
25945 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25946 * function call will be the scope provided or the current node. The arguments to the function
25947 * will be the args provided or the current node. If the function returns false at any point,
25948 * the iteration stops.
25949 * @param {Function} fn The function to call
25950 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25951 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25953 eachChild : function(fn, scope, args){
25954 var cs = this.childNodes;
25955 for(var i = 0, len = cs.length; i < len; i++) {
25956 if(fn.call(scope || this, args || cs[i]) === false){
25963 * Finds the first child that has the attribute with the specified value.
25964 * @param {String} attribute The attribute name
25965 * @param {Mixed} value The value to search for
25966 * @return {Node} The found child or null if none was found
25968 findChild : function(attribute, value){
25969 var cs = this.childNodes;
25970 for(var i = 0, len = cs.length; i < len; i++) {
25971 if(cs[i].attributes[attribute] == value){
25979 * Finds the first child by a custom function. The child matches if the function passed
25981 * @param {Function} fn
25982 * @param {Object} scope (optional)
25983 * @return {Node} The found child or null if none was found
25985 findChildBy : function(fn, scope){
25986 var cs = this.childNodes;
25987 for(var i = 0, len = cs.length; i < len; i++) {
25988 if(fn.call(scope||cs[i], cs[i]) === true){
25996 * Sorts this nodes children using the supplied sort function
25997 * @param {Function} fn
25998 * @param {Object} scope (optional)
26000 sort : function(fn, scope){
26001 var cs = this.childNodes;
26002 var len = cs.length;
26004 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
26006 for(var i = 0; i < len; i++){
26008 n.previousSibling = cs[i-1];
26009 n.nextSibling = cs[i+1];
26011 this.setFirstChild(n);
26014 this.setLastChild(n);
26021 * Returns true if this node is an ancestor (at any point) of the passed node.
26022 * @param {Node} node
26023 * @return {Boolean}
26025 contains : function(node){
26026 return node.isAncestor(this);
26030 * Returns true if the passed node is an ancestor (at any point) of this node.
26031 * @param {Node} node
26032 * @return {Boolean}
26034 isAncestor : function(node){
26035 var p = this.parentNode;
26045 toString : function(){
26046 return "[Node"+(this.id?" "+this.id:"")+"]";
26050 * Ext JS Library 1.1.1
26051 * Copyright(c) 2006-2007, Ext JS, LLC.
26053 * Originally Released Under LGPL - original licence link has changed is not relivant.
26056 * <script type="text/javascript">
26061 * @class Roo.Shadow
26062 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26063 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26064 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26066 * Create a new Shadow
26067 * @param {Object} config The config object
26069 Roo.Shadow = function(config){
26070 Roo.apply(this, config);
26071 if(typeof this.mode != "string"){
26072 this.mode = this.defaultMode;
26074 var o = this.offset, a = {h: 0};
26075 var rad = Math.floor(this.offset/2);
26076 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26082 a.l -= this.offset + rad;
26083 a.t -= this.offset + rad;
26094 a.l -= (this.offset - rad);
26095 a.t -= this.offset + rad;
26097 a.w -= (this.offset - rad)*2;
26108 a.l -= (this.offset - rad);
26109 a.t -= (this.offset - rad);
26111 a.w -= (this.offset + rad + 1);
26112 a.h -= (this.offset + rad);
26121 Roo.Shadow.prototype = {
26123 * @cfg {String} mode
26124 * The shadow display mode. Supports the following options:<br />
26125 * sides: Shadow displays on both sides and bottom only<br />
26126 * frame: Shadow displays equally on all four sides<br />
26127 * drop: Traditional bottom-right drop shadow (default)
26130 * @cfg {String} offset
26131 * The number of pixels to offset the shadow from the element (defaults to 4)
26136 defaultMode: "drop",
26139 * Displays the shadow under the target element
26140 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26142 show : function(target){
26143 target = Roo.get(target);
26145 this.el = Roo.Shadow.Pool.pull();
26146 if(this.el.dom.nextSibling != target.dom){
26147 this.el.insertBefore(target);
26150 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26152 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26155 target.getLeft(true),
26156 target.getTop(true),
26160 this.el.dom.style.display = "block";
26164 * Returns true if the shadow is visible, else false
26166 isVisible : function(){
26167 return this.el ? true : false;
26171 * Direct alignment when values are already available. Show must be called at least once before
26172 * calling this method to ensure it is initialized.
26173 * @param {Number} left The target element left position
26174 * @param {Number} top The target element top position
26175 * @param {Number} width The target element width
26176 * @param {Number} height The target element height
26178 realign : function(l, t, w, h){
26182 var a = this.adjusts, d = this.el.dom, s = d.style;
26184 s.left = (l+a.l)+"px";
26185 s.top = (t+a.t)+"px";
26186 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26188 if(s.width != sws || s.height != shs){
26192 var cn = d.childNodes;
26193 var sww = Math.max(0, (sw-12))+"px";
26194 cn[0].childNodes[1].style.width = sww;
26195 cn[1].childNodes[1].style.width = sww;
26196 cn[2].childNodes[1].style.width = sww;
26197 cn[1].style.height = Math.max(0, (sh-12))+"px";
26203 * Hides this shadow
26207 this.el.dom.style.display = "none";
26208 Roo.Shadow.Pool.push(this.el);
26214 * Adjust the z-index of this shadow
26215 * @param {Number} zindex The new z-index
26217 setZIndex : function(z){
26220 this.el.setStyle("z-index", z);
26225 // Private utility class that manages the internal Shadow cache
26226 Roo.Shadow.Pool = function(){
26228 var markup = Roo.isIE ?
26229 '<div class="x-ie-shadow"></div>' :
26230 '<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>';
26233 var sh = p.shift();
26235 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26236 sh.autoBoxAdjust = false;
26241 push : function(sh){
26247 * Ext JS Library 1.1.1
26248 * Copyright(c) 2006-2007, Ext JS, LLC.
26250 * Originally Released Under LGPL - original licence link has changed is not relivant.
26253 * <script type="text/javascript">
26258 * @class Roo.SplitBar
26259 * @extends Roo.util.Observable
26260 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26264 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26265 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26266 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26267 split.minSize = 100;
26268 split.maxSize = 600;
26269 split.animate = true;
26270 split.on('moved', splitterMoved);
26273 * Create a new SplitBar
26274 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26275 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26276 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26277 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26278 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26279 position of the SplitBar).
26281 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26284 this.el = Roo.get(dragElement, true);
26285 this.el.dom.unselectable = "on";
26287 this.resizingEl = Roo.get(resizingElement, true);
26291 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26292 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26295 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26298 * The minimum size of the resizing element. (Defaults to 0)
26304 * The maximum size of the resizing element. (Defaults to 2000)
26307 this.maxSize = 2000;
26310 * Whether to animate the transition to the new size
26313 this.animate = false;
26316 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26319 this.useShim = false;
26324 if(!existingProxy){
26326 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26328 this.proxy = Roo.get(existingProxy).dom;
26331 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26334 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26337 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26340 this.dragSpecs = {};
26343 * @private The adapter to use to positon and resize elements
26345 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26346 this.adapter.init(this);
26348 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26350 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26351 this.el.addClass("x-splitbar-h");
26354 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26355 this.el.addClass("x-splitbar-v");
26361 * Fires when the splitter is moved (alias for {@link #event-moved})
26362 * @param {Roo.SplitBar} this
26363 * @param {Number} newSize the new width or height
26368 * Fires when the splitter is moved
26369 * @param {Roo.SplitBar} this
26370 * @param {Number} newSize the new width or height
26374 * @event beforeresize
26375 * Fires before the splitter is dragged
26376 * @param {Roo.SplitBar} this
26378 "beforeresize" : true,
26380 "beforeapply" : true
26383 Roo.util.Observable.call(this);
26386 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26387 onStartProxyDrag : function(x, y){
26388 this.fireEvent("beforeresize", this);
26390 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26392 o.enableDisplayMode("block");
26393 // all splitbars share the same overlay
26394 Roo.SplitBar.prototype.overlay = o;
26396 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26397 this.overlay.show();
26398 Roo.get(this.proxy).setDisplayed("block");
26399 var size = this.adapter.getElementSize(this);
26400 this.activeMinSize = this.getMinimumSize();;
26401 this.activeMaxSize = this.getMaximumSize();;
26402 var c1 = size - this.activeMinSize;
26403 var c2 = Math.max(this.activeMaxSize - size, 0);
26404 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26405 this.dd.resetConstraints();
26406 this.dd.setXConstraint(
26407 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26408 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26410 this.dd.setYConstraint(0, 0);
26412 this.dd.resetConstraints();
26413 this.dd.setXConstraint(0, 0);
26414 this.dd.setYConstraint(
26415 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26416 this.placement == Roo.SplitBar.TOP ? c2 : c1
26419 this.dragSpecs.startSize = size;
26420 this.dragSpecs.startPoint = [x, y];
26421 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26425 * @private Called after the drag operation by the DDProxy
26427 onEndProxyDrag : function(e){
26428 Roo.get(this.proxy).setDisplayed(false);
26429 var endPoint = Roo.lib.Event.getXY(e);
26431 this.overlay.hide();
26434 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26435 newSize = this.dragSpecs.startSize +
26436 (this.placement == Roo.SplitBar.LEFT ?
26437 endPoint[0] - this.dragSpecs.startPoint[0] :
26438 this.dragSpecs.startPoint[0] - endPoint[0]
26441 newSize = this.dragSpecs.startSize +
26442 (this.placement == Roo.SplitBar.TOP ?
26443 endPoint[1] - this.dragSpecs.startPoint[1] :
26444 this.dragSpecs.startPoint[1] - endPoint[1]
26447 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26448 if(newSize != this.dragSpecs.startSize){
26449 if(this.fireEvent('beforeapply', this, newSize) !== false){
26450 this.adapter.setElementSize(this, newSize);
26451 this.fireEvent("moved", this, newSize);
26452 this.fireEvent("resize", this, newSize);
26458 * Get the adapter this SplitBar uses
26459 * @return The adapter object
26461 getAdapter : function(){
26462 return this.adapter;
26466 * Set the adapter this SplitBar uses
26467 * @param {Object} adapter A SplitBar adapter object
26469 setAdapter : function(adapter){
26470 this.adapter = adapter;
26471 this.adapter.init(this);
26475 * Gets the minimum size for the resizing element
26476 * @return {Number} The minimum size
26478 getMinimumSize : function(){
26479 return this.minSize;
26483 * Sets the minimum size for the resizing element
26484 * @param {Number} minSize The minimum size
26486 setMinimumSize : function(minSize){
26487 this.minSize = minSize;
26491 * Gets the maximum size for the resizing element
26492 * @return {Number} The maximum size
26494 getMaximumSize : function(){
26495 return this.maxSize;
26499 * Sets the maximum size for the resizing element
26500 * @param {Number} maxSize The maximum size
26502 setMaximumSize : function(maxSize){
26503 this.maxSize = maxSize;
26507 * Sets the initialize size for the resizing element
26508 * @param {Number} size The initial size
26510 setCurrentSize : function(size){
26511 var oldAnimate = this.animate;
26512 this.animate = false;
26513 this.adapter.setElementSize(this, size);
26514 this.animate = oldAnimate;
26518 * Destroy this splitbar.
26519 * @param {Boolean} removeEl True to remove the element
26521 destroy : function(removeEl){
26523 this.shim.remove();
26526 this.proxy.parentNode.removeChild(this.proxy);
26534 * @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.
26536 Roo.SplitBar.createProxy = function(dir){
26537 var proxy = new Roo.Element(document.createElement("div"));
26538 proxy.unselectable();
26539 var cls = 'x-splitbar-proxy';
26540 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26541 document.body.appendChild(proxy.dom);
26546 * @class Roo.SplitBar.BasicLayoutAdapter
26547 * Default Adapter. It assumes the splitter and resizing element are not positioned
26548 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26550 Roo.SplitBar.BasicLayoutAdapter = function(){
26553 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26554 // do nothing for now
26555 init : function(s){
26559 * Called before drag operations to get the current size of the resizing element.
26560 * @param {Roo.SplitBar} s The SplitBar using this adapter
26562 getElementSize : function(s){
26563 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26564 return s.resizingEl.getWidth();
26566 return s.resizingEl.getHeight();
26571 * Called after drag operations to set the size of the resizing element.
26572 * @param {Roo.SplitBar} s The SplitBar using this adapter
26573 * @param {Number} newSize The new size to set
26574 * @param {Function} onComplete A function to be invoked when resizing is complete
26576 setElementSize : function(s, newSize, onComplete){
26577 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26579 s.resizingEl.setWidth(newSize);
26581 onComplete(s, newSize);
26584 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26589 s.resizingEl.setHeight(newSize);
26591 onComplete(s, newSize);
26594 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26601 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26602 * @extends Roo.SplitBar.BasicLayoutAdapter
26603 * Adapter that moves the splitter element to align with the resized sizing element.
26604 * Used with an absolute positioned SplitBar.
26605 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26606 * document.body, make sure you assign an id to the body element.
26608 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26609 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26610 this.container = Roo.get(container);
26613 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26614 init : function(s){
26615 this.basic.init(s);
26618 getElementSize : function(s){
26619 return this.basic.getElementSize(s);
26622 setElementSize : function(s, newSize, onComplete){
26623 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26626 moveSplitter : function(s){
26627 var yes = Roo.SplitBar;
26628 switch(s.placement){
26630 s.el.setX(s.resizingEl.getRight());
26633 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26636 s.el.setY(s.resizingEl.getBottom());
26639 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26646 * Orientation constant - Create a vertical SplitBar
26650 Roo.SplitBar.VERTICAL = 1;
26653 * Orientation constant - Create a horizontal SplitBar
26657 Roo.SplitBar.HORIZONTAL = 2;
26660 * Placement constant - The resizing element is to the left of the splitter element
26664 Roo.SplitBar.LEFT = 1;
26667 * Placement constant - The resizing element is to the right of the splitter element
26671 Roo.SplitBar.RIGHT = 2;
26674 * Placement constant - The resizing element is positioned above the splitter element
26678 Roo.SplitBar.TOP = 3;
26681 * Placement constant - The resizing element is positioned under splitter element
26685 Roo.SplitBar.BOTTOM = 4;
26688 * Ext JS Library 1.1.1
26689 * Copyright(c) 2006-2007, Ext JS, LLC.
26691 * Originally Released Under LGPL - original licence link has changed is not relivant.
26694 * <script type="text/javascript">
26699 * @extends Roo.util.Observable
26700 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26701 * This class also supports single and multi selection modes. <br>
26702 * Create a data model bound view:
26704 var store = new Roo.data.Store(...);
26706 var view = new Roo.View({
26708 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26710 singleSelect: true,
26711 selectedClass: "ydataview-selected",
26715 // listen for node click?
26716 view.on("click", function(vw, index, node, e){
26717 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26721 dataModel.load("foobar.xml");
26723 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26725 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26726 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26728 * Note: old style constructor is still suported (container, template, config)
26731 * Create a new View
26732 * @param {Object} config The config object
26735 Roo.View = function(config, depreciated_tpl, depreciated_config){
26737 this.parent = false;
26739 if (typeof(depreciated_tpl) == 'undefined') {
26740 // new way.. - universal constructor.
26741 Roo.apply(this, config);
26742 this.el = Roo.get(this.el);
26745 this.el = Roo.get(config);
26746 this.tpl = depreciated_tpl;
26747 Roo.apply(this, depreciated_config);
26749 this.wrapEl = this.el.wrap().wrap();
26750 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26753 if(typeof(this.tpl) == "string"){
26754 this.tpl = new Roo.Template(this.tpl);
26756 // support xtype ctors..
26757 this.tpl = new Roo.factory(this.tpl, Roo);
26761 this.tpl.compile();
26766 * @event beforeclick
26767 * Fires before a click is processed. Returns false to cancel the default action.
26768 * @param {Roo.View} this
26769 * @param {Number} index The index of the target node
26770 * @param {HTMLElement} node The target node
26771 * @param {Roo.EventObject} e The raw event object
26773 "beforeclick" : true,
26776 * Fires when a template node is clicked.
26777 * @param {Roo.View} this
26778 * @param {Number} index The index of the target node
26779 * @param {HTMLElement} node The target node
26780 * @param {Roo.EventObject} e The raw event object
26785 * Fires when a template node is double clicked.
26786 * @param {Roo.View} this
26787 * @param {Number} index The index of the target node
26788 * @param {HTMLElement} node The target node
26789 * @param {Roo.EventObject} e The raw event object
26793 * @event contextmenu
26794 * Fires when a template node is right clicked.
26795 * @param {Roo.View} this
26796 * @param {Number} index The index of the target node
26797 * @param {HTMLElement} node The target node
26798 * @param {Roo.EventObject} e The raw event object
26800 "contextmenu" : true,
26802 * @event selectionchange
26803 * Fires when the selected nodes change.
26804 * @param {Roo.View} this
26805 * @param {Array} selections Array of the selected nodes
26807 "selectionchange" : true,
26810 * @event beforeselect
26811 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26812 * @param {Roo.View} this
26813 * @param {HTMLElement} node The node to be selected
26814 * @param {Array} selections Array of currently selected nodes
26816 "beforeselect" : true,
26818 * @event preparedata
26819 * Fires on every row to render, to allow you to change the data.
26820 * @param {Roo.View} this
26821 * @param {Object} data to be rendered (change this)
26823 "preparedata" : true
26831 "click": this.onClick,
26832 "dblclick": this.onDblClick,
26833 "contextmenu": this.onContextMenu,
26837 this.selections = [];
26839 this.cmp = new Roo.CompositeElementLite([]);
26841 this.store = Roo.factory(this.store, Roo.data);
26842 this.setStore(this.store, true);
26845 if ( this.footer && this.footer.xtype) {
26847 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26849 this.footer.dataSource = this.store;
26850 this.footer.container = fctr;
26851 this.footer = Roo.factory(this.footer, Roo);
26852 fctr.insertFirst(this.el);
26854 // this is a bit insane - as the paging toolbar seems to detach the el..
26855 // dom.parentNode.parentNode.parentNode
26856 // they get detached?
26860 Roo.View.superclass.constructor.call(this);
26865 Roo.extend(Roo.View, Roo.util.Observable, {
26868 * @cfg {Roo.data.Store} store Data store to load data from.
26873 * @cfg {String|Roo.Element} el The container element.
26878 * @cfg {String|Roo.Template} tpl The template used by this View
26882 * @cfg {String} dataName the named area of the template to use as the data area
26883 * Works with domtemplates roo-name="name"
26887 * @cfg {String} selectedClass The css class to add to selected nodes
26889 selectedClass : "x-view-selected",
26891 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26896 * @cfg {String} text to display on mask (default Loading)
26900 * @cfg {Boolean} multiSelect Allow multiple selection
26902 multiSelect : false,
26904 * @cfg {Boolean} singleSelect Allow single selection
26906 singleSelect: false,
26909 * @cfg {Boolean} toggleSelect - selecting
26911 toggleSelect : false,
26914 * @cfg {Boolean} tickable - selecting
26919 * Returns the element this view is bound to.
26920 * @return {Roo.Element}
26922 getEl : function(){
26923 return this.wrapEl;
26929 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26931 refresh : function(){
26932 //Roo.log('refresh');
26935 // if we are using something like 'domtemplate', then
26936 // the what gets used is:
26937 // t.applySubtemplate(NAME, data, wrapping data..)
26938 // the outer template then get' applied with
26939 // the store 'extra data'
26940 // and the body get's added to the
26941 // roo-name="data" node?
26942 // <span class='roo-tpl-{name}'></span> ?????
26946 this.clearSelections();
26947 this.el.update("");
26949 var records = this.store.getRange();
26950 if(records.length < 1) {
26952 // is this valid?? = should it render a template??
26954 this.el.update(this.emptyText);
26958 if (this.dataName) {
26959 this.el.update(t.apply(this.store.meta)); //????
26960 el = this.el.child('.roo-tpl-' + this.dataName);
26963 for(var i = 0, len = records.length; i < len; i++){
26964 var data = this.prepareData(records[i].data, i, records[i]);
26965 this.fireEvent("preparedata", this, data, i, records[i]);
26967 var d = Roo.apply({}, data);
26970 Roo.apply(d, {'roo-id' : Roo.id()});
26974 Roo.each(this.parent.item, function(item){
26975 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26978 Roo.apply(d, {'roo-data-checked' : 'checked'});
26982 html[html.length] = Roo.util.Format.trim(
26984 t.applySubtemplate(this.dataName, d, this.store.meta) :
26991 el.update(html.join(""));
26992 this.nodes = el.dom.childNodes;
26993 this.updateIndexes(0);
26998 * Function to override to reformat the data that is sent to
26999 * the template for each node.
27000 * DEPRICATED - use the preparedata event handler.
27001 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
27002 * a JSON object for an UpdateManager bound view).
27004 prepareData : function(data, index, record)
27006 this.fireEvent("preparedata", this, data, index, record);
27010 onUpdate : function(ds, record){
27011 // Roo.log('on update');
27012 this.clearSelections();
27013 var index = this.store.indexOf(record);
27014 var n = this.nodes[index];
27015 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
27016 n.parentNode.removeChild(n);
27017 this.updateIndexes(index, index);
27023 onAdd : function(ds, records, index)
27025 //Roo.log(['on Add', ds, records, index] );
27026 this.clearSelections();
27027 if(this.nodes.length == 0){
27031 var n = this.nodes[index];
27032 for(var i = 0, len = records.length; i < len; i++){
27033 var d = this.prepareData(records[i].data, i, records[i]);
27035 this.tpl.insertBefore(n, d);
27038 this.tpl.append(this.el, d);
27041 this.updateIndexes(index);
27044 onRemove : function(ds, record, index){
27045 // Roo.log('onRemove');
27046 this.clearSelections();
27047 var el = this.dataName ?
27048 this.el.child('.roo-tpl-' + this.dataName) :
27051 el.dom.removeChild(this.nodes[index]);
27052 this.updateIndexes(index);
27056 * Refresh an individual node.
27057 * @param {Number} index
27059 refreshNode : function(index){
27060 this.onUpdate(this.store, this.store.getAt(index));
27063 updateIndexes : function(startIndex, endIndex){
27064 var ns = this.nodes;
27065 startIndex = startIndex || 0;
27066 endIndex = endIndex || ns.length - 1;
27067 for(var i = startIndex; i <= endIndex; i++){
27068 ns[i].nodeIndex = i;
27073 * Changes the data store this view uses and refresh the view.
27074 * @param {Store} store
27076 setStore : function(store, initial){
27077 if(!initial && this.store){
27078 this.store.un("datachanged", this.refresh);
27079 this.store.un("add", this.onAdd);
27080 this.store.un("remove", this.onRemove);
27081 this.store.un("update", this.onUpdate);
27082 this.store.un("clear", this.refresh);
27083 this.store.un("beforeload", this.onBeforeLoad);
27084 this.store.un("load", this.onLoad);
27085 this.store.un("loadexception", this.onLoad);
27089 store.on("datachanged", this.refresh, this);
27090 store.on("add", this.onAdd, this);
27091 store.on("remove", this.onRemove, this);
27092 store.on("update", this.onUpdate, this);
27093 store.on("clear", this.refresh, this);
27094 store.on("beforeload", this.onBeforeLoad, this);
27095 store.on("load", this.onLoad, this);
27096 store.on("loadexception", this.onLoad, this);
27104 * onbeforeLoad - masks the loading area.
27107 onBeforeLoad : function(store,opts)
27109 //Roo.log('onBeforeLoad');
27111 this.el.update("");
27113 this.el.mask(this.mask ? this.mask : "Loading" );
27115 onLoad : function ()
27122 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27123 * @param {HTMLElement} node
27124 * @return {HTMLElement} The template node
27126 findItemFromChild : function(node){
27127 var el = this.dataName ?
27128 this.el.child('.roo-tpl-' + this.dataName,true) :
27131 if(!node || node.parentNode == el){
27134 var p = node.parentNode;
27135 while(p && p != el){
27136 if(p.parentNode == el){
27145 onClick : function(e){
27146 var item = this.findItemFromChild(e.getTarget());
27148 var index = this.indexOf(item);
27149 if(this.onItemClick(item, index, e) !== false){
27150 this.fireEvent("click", this, index, item, e);
27153 this.clearSelections();
27158 onContextMenu : function(e){
27159 var item = this.findItemFromChild(e.getTarget());
27161 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27166 onDblClick : function(e){
27167 var item = this.findItemFromChild(e.getTarget());
27169 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27173 onItemClick : function(item, index, e)
27175 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27178 if (this.toggleSelect) {
27179 var m = this.isSelected(item) ? 'unselect' : 'select';
27182 _t[m](item, true, false);
27185 if(this.multiSelect || this.singleSelect){
27186 if(this.multiSelect && e.shiftKey && this.lastSelection){
27187 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27189 this.select(item, this.multiSelect && e.ctrlKey);
27190 this.lastSelection = item;
27193 if(!this.tickable){
27194 e.preventDefault();
27202 * Get the number of selected nodes.
27205 getSelectionCount : function(){
27206 return this.selections.length;
27210 * Get the currently selected nodes.
27211 * @return {Array} An array of HTMLElements
27213 getSelectedNodes : function(){
27214 return this.selections;
27218 * Get the indexes of the selected nodes.
27221 getSelectedIndexes : function(){
27222 var indexes = [], s = this.selections;
27223 for(var i = 0, len = s.length; i < len; i++){
27224 indexes.push(s[i].nodeIndex);
27230 * Clear all selections
27231 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27233 clearSelections : function(suppressEvent){
27234 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27235 this.cmp.elements = this.selections;
27236 this.cmp.removeClass(this.selectedClass);
27237 this.selections = [];
27238 if(!suppressEvent){
27239 this.fireEvent("selectionchange", this, this.selections);
27245 * Returns true if the passed node is selected
27246 * @param {HTMLElement/Number} node The node or node index
27247 * @return {Boolean}
27249 isSelected : function(node){
27250 var s = this.selections;
27254 node = this.getNode(node);
27255 return s.indexOf(node) !== -1;
27260 * @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
27261 * @param {Boolean} keepExisting (optional) true to keep existing selections
27262 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27264 select : function(nodeInfo, keepExisting, suppressEvent){
27265 if(nodeInfo instanceof Array){
27267 this.clearSelections(true);
27269 for(var i = 0, len = nodeInfo.length; i < len; i++){
27270 this.select(nodeInfo[i], true, true);
27274 var node = this.getNode(nodeInfo);
27275 if(!node || this.isSelected(node)){
27276 return; // already selected.
27279 this.clearSelections(true);
27282 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27283 Roo.fly(node).addClass(this.selectedClass);
27284 this.selections.push(node);
27285 if(!suppressEvent){
27286 this.fireEvent("selectionchange", this, this.selections);
27294 * @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
27295 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27296 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27298 unselect : function(nodeInfo, keepExisting, suppressEvent)
27300 if(nodeInfo instanceof Array){
27301 Roo.each(this.selections, function(s) {
27302 this.unselect(s, nodeInfo);
27306 var node = this.getNode(nodeInfo);
27307 if(!node || !this.isSelected(node)){
27308 //Roo.log("not selected");
27309 return; // not selected.
27313 Roo.each(this.selections, function(s) {
27315 Roo.fly(node).removeClass(this.selectedClass);
27322 this.selections= ns;
27323 this.fireEvent("selectionchange", this, this.selections);
27327 * Gets a template node.
27328 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27329 * @return {HTMLElement} The node or null if it wasn't found
27331 getNode : function(nodeInfo){
27332 if(typeof nodeInfo == "string"){
27333 return document.getElementById(nodeInfo);
27334 }else if(typeof nodeInfo == "number"){
27335 return this.nodes[nodeInfo];
27341 * Gets a range template nodes.
27342 * @param {Number} startIndex
27343 * @param {Number} endIndex
27344 * @return {Array} An array of nodes
27346 getNodes : function(start, end){
27347 var ns = this.nodes;
27348 start = start || 0;
27349 end = typeof end == "undefined" ? ns.length - 1 : end;
27352 for(var i = start; i <= end; i++){
27356 for(var i = start; i >= end; i--){
27364 * Finds the index of the passed node
27365 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27366 * @return {Number} The index of the node or -1
27368 indexOf : function(node){
27369 node = this.getNode(node);
27370 if(typeof node.nodeIndex == "number"){
27371 return node.nodeIndex;
27373 var ns = this.nodes;
27374 for(var i = 0, len = ns.length; i < len; i++){
27384 * Ext JS Library 1.1.1
27385 * Copyright(c) 2006-2007, Ext JS, LLC.
27387 * Originally Released Under LGPL - original licence link has changed is not relivant.
27390 * <script type="text/javascript">
27394 * @class Roo.JsonView
27395 * @extends Roo.View
27396 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27398 var view = new Roo.JsonView({
27399 container: "my-element",
27400 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27405 // listen for node click?
27406 view.on("click", function(vw, index, node, e){
27407 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27410 // direct load of JSON data
27411 view.load("foobar.php");
27413 // Example from my blog list
27414 var tpl = new Roo.Template(
27415 '<div class="entry">' +
27416 '<a class="entry-title" href="{link}">{title}</a>' +
27417 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27418 "</div><hr />"
27421 var moreView = new Roo.JsonView({
27422 container : "entry-list",
27426 moreView.on("beforerender", this.sortEntries, this);
27428 url: "/blog/get-posts.php",
27429 params: "allposts=true",
27430 text: "Loading Blog Entries..."
27434 * Note: old code is supported with arguments : (container, template, config)
27438 * Create a new JsonView
27440 * @param {Object} config The config object
27443 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27446 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27448 var um = this.el.getUpdateManager();
27449 um.setRenderer(this);
27450 um.on("update", this.onLoad, this);
27451 um.on("failure", this.onLoadException, this);
27454 * @event beforerender
27455 * Fires before rendering of the downloaded JSON data.
27456 * @param {Roo.JsonView} this
27457 * @param {Object} data The JSON data loaded
27461 * Fires when data is loaded.
27462 * @param {Roo.JsonView} this
27463 * @param {Object} data The JSON data loaded
27464 * @param {Object} response The raw Connect response object
27467 * @event loadexception
27468 * Fires when loading fails.
27469 * @param {Roo.JsonView} this
27470 * @param {Object} response The raw Connect response object
27473 'beforerender' : true,
27475 'loadexception' : true
27478 Roo.extend(Roo.JsonView, Roo.View, {
27480 * @type {String} The root property in the loaded JSON object that contains the data
27485 * Refreshes the view.
27487 refresh : function(){
27488 this.clearSelections();
27489 this.el.update("");
27491 var o = this.jsonData;
27492 if(o && o.length > 0){
27493 for(var i = 0, len = o.length; i < len; i++){
27494 var data = this.prepareData(o[i], i, o);
27495 html[html.length] = this.tpl.apply(data);
27498 html.push(this.emptyText);
27500 this.el.update(html.join(""));
27501 this.nodes = this.el.dom.childNodes;
27502 this.updateIndexes(0);
27506 * 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.
27507 * @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:
27510 url: "your-url.php",
27511 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27512 callback: yourFunction,
27513 scope: yourObject, //(optional scope)
27516 text: "Loading...",
27521 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27522 * 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.
27523 * @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}
27524 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27525 * @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.
27528 var um = this.el.getUpdateManager();
27529 um.update.apply(um, arguments);
27532 // note - render is a standard framework call...
27533 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27534 render : function(el, response){
27536 this.clearSelections();
27537 this.el.update("");
27540 if (response != '') {
27541 o = Roo.util.JSON.decode(response.responseText);
27544 o = o[this.jsonRoot];
27550 * The current JSON data or null
27553 this.beforeRender();
27558 * Get the number of records in the current JSON dataset
27561 getCount : function(){
27562 return this.jsonData ? this.jsonData.length : 0;
27566 * Returns the JSON object for the specified node(s)
27567 * @param {HTMLElement/Array} node The node or an array of nodes
27568 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27569 * you get the JSON object for the node
27571 getNodeData : function(node){
27572 if(node instanceof Array){
27574 for(var i = 0, len = node.length; i < len; i++){
27575 data.push(this.getNodeData(node[i]));
27579 return this.jsonData[this.indexOf(node)] || null;
27582 beforeRender : function(){
27583 this.snapshot = this.jsonData;
27585 this.sort.apply(this, this.sortInfo);
27587 this.fireEvent("beforerender", this, this.jsonData);
27590 onLoad : function(el, o){
27591 this.fireEvent("load", this, this.jsonData, o);
27594 onLoadException : function(el, o){
27595 this.fireEvent("loadexception", this, o);
27599 * Filter the data by a specific property.
27600 * @param {String} property A property on your JSON objects
27601 * @param {String/RegExp} value Either string that the property values
27602 * should start with, or a RegExp to test against the property
27604 filter : function(property, value){
27607 var ss = this.snapshot;
27608 if(typeof value == "string"){
27609 var vlen = value.length;
27611 this.clearFilter();
27614 value = value.toLowerCase();
27615 for(var i = 0, len = ss.length; i < len; i++){
27617 if(o[property].substr(0, vlen).toLowerCase() == value){
27621 } else if(value.exec){ // regex?
27622 for(var i = 0, len = ss.length; i < len; i++){
27624 if(value.test(o[property])){
27631 this.jsonData = data;
27637 * Filter by a function. The passed function will be called with each
27638 * object in the current dataset. If the function returns true the value is kept,
27639 * otherwise it is filtered.
27640 * @param {Function} fn
27641 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27643 filterBy : function(fn, scope){
27646 var ss = this.snapshot;
27647 for(var i = 0, len = ss.length; i < len; i++){
27649 if(fn.call(scope || this, o)){
27653 this.jsonData = data;
27659 * Clears the current filter.
27661 clearFilter : function(){
27662 if(this.snapshot && this.jsonData != this.snapshot){
27663 this.jsonData = this.snapshot;
27670 * Sorts the data for this view and refreshes it.
27671 * @param {String} property A property on your JSON objects to sort on
27672 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27673 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27675 sort : function(property, dir, sortType){
27676 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27679 var dsc = dir && dir.toLowerCase() == "desc";
27680 var f = function(o1, o2){
27681 var v1 = sortType ? sortType(o1[p]) : o1[p];
27682 var v2 = sortType ? sortType(o2[p]) : o2[p];
27685 return dsc ? +1 : -1;
27686 } else if(v1 > v2){
27687 return dsc ? -1 : +1;
27692 this.jsonData.sort(f);
27694 if(this.jsonData != this.snapshot){
27695 this.snapshot.sort(f);
27701 * Ext JS Library 1.1.1
27702 * Copyright(c) 2006-2007, Ext JS, LLC.
27704 * Originally Released Under LGPL - original licence link has changed is not relivant.
27707 * <script type="text/javascript">
27712 * @class Roo.ColorPalette
27713 * @extends Roo.Component
27714 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27715 * Here's an example of typical usage:
27717 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27718 cp.render('my-div');
27720 cp.on('select', function(palette, selColor){
27721 // do something with selColor
27725 * Create a new ColorPalette
27726 * @param {Object} config The config object
27728 Roo.ColorPalette = function(config){
27729 Roo.ColorPalette.superclass.constructor.call(this, config);
27733 * Fires when a color is selected
27734 * @param {ColorPalette} this
27735 * @param {String} color The 6-digit color hex code (without the # symbol)
27741 this.on("select", this.handler, this.scope, true);
27744 Roo.extend(Roo.ColorPalette, Roo.Component, {
27746 * @cfg {String} itemCls
27747 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27749 itemCls : "x-color-palette",
27751 * @cfg {String} value
27752 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27753 * the hex codes are case-sensitive.
27756 clickEvent:'click',
27758 ctype: "Roo.ColorPalette",
27761 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27763 allowReselect : false,
27766 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27767 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27768 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27769 * of colors with the width setting until the box is symmetrical.</p>
27770 * <p>You can override individual colors if needed:</p>
27772 var cp = new Roo.ColorPalette();
27773 cp.colors[0] = "FF0000"; // change the first box to red
27776 Or you can provide a custom array of your own for complete control:
27778 var cp = new Roo.ColorPalette();
27779 cp.colors = ["000000", "993300", "333300"];
27784 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27785 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27786 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27787 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27788 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27792 onRender : function(container, position){
27793 var t = new Roo.MasterTemplate(
27794 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27796 var c = this.colors;
27797 for(var i = 0, len = c.length; i < len; i++){
27800 var el = document.createElement("div");
27801 el.className = this.itemCls;
27803 container.dom.insertBefore(el, position);
27804 this.el = Roo.get(el);
27805 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27806 if(this.clickEvent != 'click'){
27807 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27812 afterRender : function(){
27813 Roo.ColorPalette.superclass.afterRender.call(this);
27815 var s = this.value;
27822 handleClick : function(e, t){
27823 e.preventDefault();
27824 if(!this.disabled){
27825 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27826 this.select(c.toUpperCase());
27831 * Selects the specified color in the palette (fires the select event)
27832 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27834 select : function(color){
27835 color = color.replace("#", "");
27836 if(color != this.value || this.allowReselect){
27839 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27841 el.child("a.color-"+color).addClass("x-color-palette-sel");
27842 this.value = color;
27843 this.fireEvent("select", this, color);
27848 * Ext JS Library 1.1.1
27849 * Copyright(c) 2006-2007, Ext JS, LLC.
27851 * Originally Released Under LGPL - original licence link has changed is not relivant.
27854 * <script type="text/javascript">
27858 * @class Roo.DatePicker
27859 * @extends Roo.Component
27860 * Simple date picker class.
27862 * Create a new DatePicker
27863 * @param {Object} config The config object
27865 Roo.DatePicker = function(config){
27866 Roo.DatePicker.superclass.constructor.call(this, config);
27868 this.value = config && config.value ?
27869 config.value.clearTime() : new Date().clearTime();
27874 * Fires when a date is selected
27875 * @param {DatePicker} this
27876 * @param {Date} date The selected date
27880 * @event monthchange
27881 * Fires when the displayed month changes
27882 * @param {DatePicker} this
27883 * @param {Date} date The selected month
27885 'monthchange': true
27889 this.on("select", this.handler, this.scope || this);
27891 // build the disabledDatesRE
27892 if(!this.disabledDatesRE && this.disabledDates){
27893 var dd = this.disabledDates;
27895 for(var i = 0; i < dd.length; i++){
27897 if(i != dd.length-1) {
27901 this.disabledDatesRE = new RegExp(re + ")");
27905 Roo.extend(Roo.DatePicker, Roo.Component, {
27907 * @cfg {String} todayText
27908 * The text to display on the button that selects the current date (defaults to "Today")
27910 todayText : "Today",
27912 * @cfg {String} okText
27913 * The text to display on the ok button
27915 okText : " OK ", //   to give the user extra clicking room
27917 * @cfg {String} cancelText
27918 * The text to display on the cancel button
27920 cancelText : "Cancel",
27922 * @cfg {String} todayTip
27923 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27925 todayTip : "{0} (Spacebar)",
27927 * @cfg {Date} minDate
27928 * Minimum allowable date (JavaScript date object, defaults to null)
27932 * @cfg {Date} maxDate
27933 * Maximum allowable date (JavaScript date object, defaults to null)
27937 * @cfg {String} minText
27938 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27940 minText : "This date is before the minimum date",
27942 * @cfg {String} maxText
27943 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27945 maxText : "This date is after the maximum date",
27947 * @cfg {String} format
27948 * The default date format string which can be overriden for localization support. The format must be
27949 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27953 * @cfg {Array} disabledDays
27954 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27956 disabledDays : null,
27958 * @cfg {String} disabledDaysText
27959 * The tooltip to display when the date falls on a disabled day (defaults to "")
27961 disabledDaysText : "",
27963 * @cfg {RegExp} disabledDatesRE
27964 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27966 disabledDatesRE : null,
27968 * @cfg {String} disabledDatesText
27969 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27971 disabledDatesText : "",
27973 * @cfg {Boolean} constrainToViewport
27974 * True to constrain the date picker to the viewport (defaults to true)
27976 constrainToViewport : true,
27978 * @cfg {Array} monthNames
27979 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27981 monthNames : Date.monthNames,
27983 * @cfg {Array} dayNames
27984 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27986 dayNames : Date.dayNames,
27988 * @cfg {String} nextText
27989 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27991 nextText: 'Next Month (Control+Right)',
27993 * @cfg {String} prevText
27994 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27996 prevText: 'Previous Month (Control+Left)',
27998 * @cfg {String} monthYearText
27999 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
28001 monthYearText: 'Choose a month (Control+Up/Down to move years)',
28003 * @cfg {Number} startDay
28004 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
28008 * @cfg {Bool} showClear
28009 * Show a clear button (usefull for date form elements that can be blank.)
28015 * Sets the value of the date field
28016 * @param {Date} value The date to set
28018 setValue : function(value){
28019 var old = this.value;
28021 if (typeof(value) == 'string') {
28023 value = Date.parseDate(value, this.format);
28026 value = new Date();
28029 this.value = value.clearTime(true);
28031 this.update(this.value);
28036 * Gets the current selected value of the date field
28037 * @return {Date} The selected date
28039 getValue : function(){
28044 focus : function(){
28046 this.update(this.activeDate);
28051 onRender : function(container, position){
28054 '<table cellspacing="0">',
28055 '<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>',
28056 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28057 var dn = this.dayNames;
28058 for(var i = 0; i < 7; i++){
28059 var d = this.startDay+i;
28063 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28065 m[m.length] = "</tr></thead><tbody><tr>";
28066 for(var i = 0; i < 42; i++) {
28067 if(i % 7 == 0 && i != 0){
28068 m[m.length] = "</tr><tr>";
28070 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28072 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28073 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28075 var el = document.createElement("div");
28076 el.className = "x-date-picker";
28077 el.innerHTML = m.join("");
28079 container.dom.insertBefore(el, position);
28081 this.el = Roo.get(el);
28082 this.eventEl = Roo.get(el.firstChild);
28084 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28085 handler: this.showPrevMonth,
28087 preventDefault:true,
28091 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28092 handler: this.showNextMonth,
28094 preventDefault:true,
28098 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28100 this.monthPicker = this.el.down('div.x-date-mp');
28101 this.monthPicker.enableDisplayMode('block');
28103 var kn = new Roo.KeyNav(this.eventEl, {
28104 "left" : function(e){
28106 this.showPrevMonth() :
28107 this.update(this.activeDate.add("d", -1));
28110 "right" : function(e){
28112 this.showNextMonth() :
28113 this.update(this.activeDate.add("d", 1));
28116 "up" : function(e){
28118 this.showNextYear() :
28119 this.update(this.activeDate.add("d", -7));
28122 "down" : function(e){
28124 this.showPrevYear() :
28125 this.update(this.activeDate.add("d", 7));
28128 "pageUp" : function(e){
28129 this.showNextMonth();
28132 "pageDown" : function(e){
28133 this.showPrevMonth();
28136 "enter" : function(e){
28137 e.stopPropagation();
28144 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28146 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28148 this.el.unselectable();
28150 this.cells = this.el.select("table.x-date-inner tbody td");
28151 this.textNodes = this.el.query("table.x-date-inner tbody span");
28153 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28155 tooltip: this.monthYearText
28158 this.mbtn.on('click', this.showMonthPicker, this);
28159 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28162 var today = (new Date()).dateFormat(this.format);
28164 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28165 if (this.showClear) {
28166 baseTb.add( new Roo.Toolbar.Fill());
28169 text: String.format(this.todayText, today),
28170 tooltip: String.format(this.todayTip, today),
28171 handler: this.selectToday,
28175 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28178 if (this.showClear) {
28180 baseTb.add( new Roo.Toolbar.Fill());
28183 cls: 'x-btn-icon x-btn-clear',
28184 handler: function() {
28186 this.fireEvent("select", this, '');
28196 this.update(this.value);
28199 createMonthPicker : function(){
28200 if(!this.monthPicker.dom.firstChild){
28201 var buf = ['<table border="0" cellspacing="0">'];
28202 for(var i = 0; i < 6; i++){
28204 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28205 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28207 '<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>' :
28208 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28212 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28214 '</button><button type="button" class="x-date-mp-cancel">',
28216 '</button></td></tr>',
28219 this.monthPicker.update(buf.join(''));
28220 this.monthPicker.on('click', this.onMonthClick, this);
28221 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28223 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28224 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28226 this.mpMonths.each(function(m, a, i){
28229 m.dom.xmonth = 5 + Math.round(i * .5);
28231 m.dom.xmonth = Math.round((i-1) * .5);
28237 showMonthPicker : function(){
28238 this.createMonthPicker();
28239 var size = this.el.getSize();
28240 this.monthPicker.setSize(size);
28241 this.monthPicker.child('table').setSize(size);
28243 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28244 this.updateMPMonth(this.mpSelMonth);
28245 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28246 this.updateMPYear(this.mpSelYear);
28248 this.monthPicker.slideIn('t', {duration:.2});
28251 updateMPYear : function(y){
28253 var ys = this.mpYears.elements;
28254 for(var i = 1; i <= 10; i++){
28255 var td = ys[i-1], y2;
28257 y2 = y + Math.round(i * .5);
28258 td.firstChild.innerHTML = y2;
28261 y2 = y - (5-Math.round(i * .5));
28262 td.firstChild.innerHTML = y2;
28265 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28269 updateMPMonth : function(sm){
28270 this.mpMonths.each(function(m, a, i){
28271 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28275 selectMPMonth: function(m){
28279 onMonthClick : function(e, t){
28281 var el = new Roo.Element(t), pn;
28282 if(el.is('button.x-date-mp-cancel')){
28283 this.hideMonthPicker();
28285 else if(el.is('button.x-date-mp-ok')){
28286 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28287 this.hideMonthPicker();
28289 else if(pn = el.up('td.x-date-mp-month', 2)){
28290 this.mpMonths.removeClass('x-date-mp-sel');
28291 pn.addClass('x-date-mp-sel');
28292 this.mpSelMonth = pn.dom.xmonth;
28294 else if(pn = el.up('td.x-date-mp-year', 2)){
28295 this.mpYears.removeClass('x-date-mp-sel');
28296 pn.addClass('x-date-mp-sel');
28297 this.mpSelYear = pn.dom.xyear;
28299 else if(el.is('a.x-date-mp-prev')){
28300 this.updateMPYear(this.mpyear-10);
28302 else if(el.is('a.x-date-mp-next')){
28303 this.updateMPYear(this.mpyear+10);
28307 onMonthDblClick : function(e, t){
28309 var el = new Roo.Element(t), pn;
28310 if(pn = el.up('td.x-date-mp-month', 2)){
28311 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28312 this.hideMonthPicker();
28314 else if(pn = el.up('td.x-date-mp-year', 2)){
28315 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28316 this.hideMonthPicker();
28320 hideMonthPicker : function(disableAnim){
28321 if(this.monthPicker){
28322 if(disableAnim === true){
28323 this.monthPicker.hide();
28325 this.monthPicker.slideOut('t', {duration:.2});
28331 showPrevMonth : function(e){
28332 this.update(this.activeDate.add("mo", -1));
28336 showNextMonth : function(e){
28337 this.update(this.activeDate.add("mo", 1));
28341 showPrevYear : function(){
28342 this.update(this.activeDate.add("y", -1));
28346 showNextYear : function(){
28347 this.update(this.activeDate.add("y", 1));
28351 handleMouseWheel : function(e){
28352 var delta = e.getWheelDelta();
28354 this.showPrevMonth();
28356 } else if(delta < 0){
28357 this.showNextMonth();
28363 handleDateClick : function(e, t){
28365 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28366 this.setValue(new Date(t.dateValue));
28367 this.fireEvent("select", this, this.value);
28372 selectToday : function(){
28373 this.setValue(new Date().clearTime());
28374 this.fireEvent("select", this, this.value);
28378 update : function(date)
28380 var vd = this.activeDate;
28381 this.activeDate = date;
28383 var t = date.getTime();
28384 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28385 this.cells.removeClass("x-date-selected");
28386 this.cells.each(function(c){
28387 if(c.dom.firstChild.dateValue == t){
28388 c.addClass("x-date-selected");
28389 setTimeout(function(){
28390 try{c.dom.firstChild.focus();}catch(e){}
28399 var days = date.getDaysInMonth();
28400 var firstOfMonth = date.getFirstDateOfMonth();
28401 var startingPos = firstOfMonth.getDay()-this.startDay;
28403 if(startingPos <= this.startDay){
28407 var pm = date.add("mo", -1);
28408 var prevStart = pm.getDaysInMonth()-startingPos;
28410 var cells = this.cells.elements;
28411 var textEls = this.textNodes;
28412 days += startingPos;
28414 // convert everything to numbers so it's fast
28415 var day = 86400000;
28416 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28417 var today = new Date().clearTime().getTime();
28418 var sel = date.clearTime().getTime();
28419 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28420 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28421 var ddMatch = this.disabledDatesRE;
28422 var ddText = this.disabledDatesText;
28423 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28424 var ddaysText = this.disabledDaysText;
28425 var format = this.format;
28427 var setCellClass = function(cal, cell){
28429 var t = d.getTime();
28430 cell.firstChild.dateValue = t;
28432 cell.className += " x-date-today";
28433 cell.title = cal.todayText;
28436 cell.className += " x-date-selected";
28437 setTimeout(function(){
28438 try{cell.firstChild.focus();}catch(e){}
28443 cell.className = " x-date-disabled";
28444 cell.title = cal.minText;
28448 cell.className = " x-date-disabled";
28449 cell.title = cal.maxText;
28453 if(ddays.indexOf(d.getDay()) != -1){
28454 cell.title = ddaysText;
28455 cell.className = " x-date-disabled";
28458 if(ddMatch && format){
28459 var fvalue = d.dateFormat(format);
28460 if(ddMatch.test(fvalue)){
28461 cell.title = ddText.replace("%0", fvalue);
28462 cell.className = " x-date-disabled";
28468 for(; i < startingPos; i++) {
28469 textEls[i].innerHTML = (++prevStart);
28470 d.setDate(d.getDate()+1);
28471 cells[i].className = "x-date-prevday";
28472 setCellClass(this, cells[i]);
28474 for(; i < days; i++){
28475 intDay = i - startingPos + 1;
28476 textEls[i].innerHTML = (intDay);
28477 d.setDate(d.getDate()+1);
28478 cells[i].className = "x-date-active";
28479 setCellClass(this, cells[i]);
28482 for(; i < 42; i++) {
28483 textEls[i].innerHTML = (++extraDays);
28484 d.setDate(d.getDate()+1);
28485 cells[i].className = "x-date-nextday";
28486 setCellClass(this, cells[i]);
28489 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28490 this.fireEvent('monthchange', this, date);
28492 if(!this.internalRender){
28493 var main = this.el.dom.firstChild;
28494 var w = main.offsetWidth;
28495 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28496 Roo.fly(main).setWidth(w);
28497 this.internalRender = true;
28498 // opera does not respect the auto grow header center column
28499 // then, after it gets a width opera refuses to recalculate
28500 // without a second pass
28501 if(Roo.isOpera && !this.secondPass){
28502 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28503 this.secondPass = true;
28504 this.update.defer(10, this, [date]);
28512 * Ext JS Library 1.1.1
28513 * Copyright(c) 2006-2007, Ext JS, LLC.
28515 * Originally Released Under LGPL - original licence link has changed is not relivant.
28518 * <script type="text/javascript">
28521 * @class Roo.TabPanel
28522 * @extends Roo.util.Observable
28523 * A lightweight tab container.
28527 // basic tabs 1, built from existing content
28528 var tabs = new Roo.TabPanel("tabs1");
28529 tabs.addTab("script", "View Script");
28530 tabs.addTab("markup", "View Markup");
28531 tabs.activate("script");
28533 // more advanced tabs, built from javascript
28534 var jtabs = new Roo.TabPanel("jtabs");
28535 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28537 // set up the UpdateManager
28538 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28539 var updater = tab2.getUpdateManager();
28540 updater.setDefaultUrl("ajax1.htm");
28541 tab2.on('activate', updater.refresh, updater, true);
28543 // Use setUrl for Ajax loading
28544 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28545 tab3.setUrl("ajax2.htm", null, true);
28548 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28551 jtabs.activate("jtabs-1");
28554 * Create a new TabPanel.
28555 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28556 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28558 Roo.TabPanel = function(container, config){
28560 * The container element for this TabPanel.
28561 * @type Roo.Element
28563 this.el = Roo.get(container, true);
28565 if(typeof config == "boolean"){
28566 this.tabPosition = config ? "bottom" : "top";
28568 Roo.apply(this, config);
28571 if(this.tabPosition == "bottom"){
28572 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28573 this.el.addClass("x-tabs-bottom");
28575 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28576 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28577 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28579 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28581 if(this.tabPosition != "bottom"){
28582 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28583 * @type Roo.Element
28585 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28586 this.el.addClass("x-tabs-top");
28590 this.bodyEl.setStyle("position", "relative");
28592 this.active = null;
28593 this.activateDelegate = this.activate.createDelegate(this);
28598 * Fires when the active tab changes
28599 * @param {Roo.TabPanel} this
28600 * @param {Roo.TabPanelItem} activePanel The new active tab
28604 * @event beforetabchange
28605 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28606 * @param {Roo.TabPanel} this
28607 * @param {Object} e Set cancel to true on this object to cancel the tab change
28608 * @param {Roo.TabPanelItem} tab The tab being changed to
28610 "beforetabchange" : true
28613 Roo.EventManager.onWindowResize(this.onResize, this);
28614 this.cpad = this.el.getPadding("lr");
28615 this.hiddenCount = 0;
28618 // toolbar on the tabbar support...
28619 if (this.toolbar) {
28620 var tcfg = this.toolbar;
28621 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28622 this.toolbar = new Roo.Toolbar(tcfg);
28623 if (Roo.isSafari) {
28624 var tbl = tcfg.container.child('table', true);
28625 tbl.setAttribute('width', '100%');
28632 Roo.TabPanel.superclass.constructor.call(this);
28635 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28637 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28639 tabPosition : "top",
28641 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28643 currentTabWidth : 0,
28645 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28649 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28653 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28655 preferredTabWidth : 175,
28657 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28659 resizeTabs : false,
28661 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28663 monitorResize : true,
28665 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28670 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28671 * @param {String} id The id of the div to use <b>or create</b>
28672 * @param {String} text The text for the tab
28673 * @param {String} content (optional) Content to put in the TabPanelItem body
28674 * @param {Boolean} closable (optional) True to create a close icon on the tab
28675 * @return {Roo.TabPanelItem} The created TabPanelItem
28677 addTab : function(id, text, content, closable){
28678 var item = new Roo.TabPanelItem(this, id, text, closable);
28679 this.addTabItem(item);
28681 item.setContent(content);
28687 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28688 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28689 * @return {Roo.TabPanelItem}
28691 getTab : function(id){
28692 return this.items[id];
28696 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28697 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28699 hideTab : function(id){
28700 var t = this.items[id];
28703 this.hiddenCount++;
28704 this.autoSizeTabs();
28709 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28710 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28712 unhideTab : function(id){
28713 var t = this.items[id];
28715 t.setHidden(false);
28716 this.hiddenCount--;
28717 this.autoSizeTabs();
28722 * Adds an existing {@link Roo.TabPanelItem}.
28723 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28725 addTabItem : function(item){
28726 this.items[item.id] = item;
28727 this.items.push(item);
28728 if(this.resizeTabs){
28729 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28730 this.autoSizeTabs();
28737 * Removes a {@link Roo.TabPanelItem}.
28738 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28740 removeTab : function(id){
28741 var items = this.items;
28742 var tab = items[id];
28743 if(!tab) { return; }
28744 var index = items.indexOf(tab);
28745 if(this.active == tab && items.length > 1){
28746 var newTab = this.getNextAvailable(index);
28751 this.stripEl.dom.removeChild(tab.pnode.dom);
28752 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28753 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28755 items.splice(index, 1);
28756 delete this.items[tab.id];
28757 tab.fireEvent("close", tab);
28758 tab.purgeListeners();
28759 this.autoSizeTabs();
28762 getNextAvailable : function(start){
28763 var items = this.items;
28765 // look for a next tab that will slide over to
28766 // replace the one being removed
28767 while(index < items.length){
28768 var item = items[++index];
28769 if(item && !item.isHidden()){
28773 // if one isn't found select the previous tab (on the left)
28776 var item = items[--index];
28777 if(item && !item.isHidden()){
28785 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28786 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28788 disableTab : function(id){
28789 var tab = this.items[id];
28790 if(tab && this.active != tab){
28796 * Enables a {@link Roo.TabPanelItem} that is disabled.
28797 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28799 enableTab : function(id){
28800 var tab = this.items[id];
28805 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28806 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28807 * @return {Roo.TabPanelItem} The TabPanelItem.
28809 activate : function(id){
28810 var tab = this.items[id];
28814 if(tab == this.active || tab.disabled){
28818 this.fireEvent("beforetabchange", this, e, tab);
28819 if(e.cancel !== true && !tab.disabled){
28821 this.active.hide();
28823 this.active = this.items[id];
28824 this.active.show();
28825 this.fireEvent("tabchange", this, this.active);
28831 * Gets the active {@link Roo.TabPanelItem}.
28832 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28834 getActiveTab : function(){
28835 return this.active;
28839 * Updates the tab body element to fit the height of the container element
28840 * for overflow scrolling
28841 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28843 syncHeight : function(targetHeight){
28844 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28845 var bm = this.bodyEl.getMargins();
28846 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28847 this.bodyEl.setHeight(newHeight);
28851 onResize : function(){
28852 if(this.monitorResize){
28853 this.autoSizeTabs();
28858 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28860 beginUpdate : function(){
28861 this.updating = true;
28865 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28867 endUpdate : function(){
28868 this.updating = false;
28869 this.autoSizeTabs();
28873 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28875 autoSizeTabs : function(){
28876 var count = this.items.length;
28877 var vcount = count - this.hiddenCount;
28878 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28881 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28882 var availWidth = Math.floor(w / vcount);
28883 var b = this.stripBody;
28884 if(b.getWidth() > w){
28885 var tabs = this.items;
28886 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28887 if(availWidth < this.minTabWidth){
28888 /*if(!this.sleft){ // incomplete scrolling code
28889 this.createScrollButtons();
28892 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28895 if(this.currentTabWidth < this.preferredTabWidth){
28896 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28902 * Returns the number of tabs in this TabPanel.
28905 getCount : function(){
28906 return this.items.length;
28910 * Resizes all the tabs to the passed width
28911 * @param {Number} The new width
28913 setTabWidth : function(width){
28914 this.currentTabWidth = width;
28915 for(var i = 0, len = this.items.length; i < len; i++) {
28916 if(!this.items[i].isHidden()) {
28917 this.items[i].setWidth(width);
28923 * Destroys this TabPanel
28924 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28926 destroy : function(removeEl){
28927 Roo.EventManager.removeResizeListener(this.onResize, this);
28928 for(var i = 0, len = this.items.length; i < len; i++){
28929 this.items[i].purgeListeners();
28931 if(removeEl === true){
28932 this.el.update("");
28939 * @class Roo.TabPanelItem
28940 * @extends Roo.util.Observable
28941 * Represents an individual item (tab plus body) in a TabPanel.
28942 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28943 * @param {String} id The id of this TabPanelItem
28944 * @param {String} text The text for the tab of this TabPanelItem
28945 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28947 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28949 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28950 * @type Roo.TabPanel
28952 this.tabPanel = tabPanel;
28954 * The id for this TabPanelItem
28959 this.disabled = false;
28963 this.loaded = false;
28964 this.closable = closable;
28967 * The body element for this TabPanelItem.
28968 * @type Roo.Element
28970 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28971 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28972 this.bodyEl.setStyle("display", "block");
28973 this.bodyEl.setStyle("zoom", "1");
28976 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28978 this.el = Roo.get(els.el, true);
28979 this.inner = Roo.get(els.inner, true);
28980 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28981 this.pnode = Roo.get(els.el.parentNode, true);
28982 this.el.on("mousedown", this.onTabMouseDown, this);
28983 this.el.on("click", this.onTabClick, this);
28986 var c = Roo.get(els.close, true);
28987 c.dom.title = this.closeText;
28988 c.addClassOnOver("close-over");
28989 c.on("click", this.closeClick, this);
28995 * Fires when this tab becomes the active tab.
28996 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28997 * @param {Roo.TabPanelItem} this
29001 * @event beforeclose
29002 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
29003 * @param {Roo.TabPanelItem} this
29004 * @param {Object} e Set cancel to true on this object to cancel the close.
29006 "beforeclose": true,
29009 * Fires when this tab is closed.
29010 * @param {Roo.TabPanelItem} this
29014 * @event deactivate
29015 * Fires when this tab is no longer the active tab.
29016 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29017 * @param {Roo.TabPanelItem} this
29019 "deactivate" : true
29021 this.hidden = false;
29023 Roo.TabPanelItem.superclass.constructor.call(this);
29026 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
29027 purgeListeners : function(){
29028 Roo.util.Observable.prototype.purgeListeners.call(this);
29029 this.el.removeAllListeners();
29032 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
29035 this.pnode.addClass("on");
29038 this.tabPanel.stripWrap.repaint();
29040 this.fireEvent("activate", this.tabPanel, this);
29044 * Returns true if this tab is the active tab.
29045 * @return {Boolean}
29047 isActive : function(){
29048 return this.tabPanel.getActiveTab() == this;
29052 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29055 this.pnode.removeClass("on");
29057 this.fireEvent("deactivate", this.tabPanel, this);
29060 hideAction : function(){
29061 this.bodyEl.hide();
29062 this.bodyEl.setStyle("position", "absolute");
29063 this.bodyEl.setLeft("-20000px");
29064 this.bodyEl.setTop("-20000px");
29067 showAction : function(){
29068 this.bodyEl.setStyle("position", "relative");
29069 this.bodyEl.setTop("");
29070 this.bodyEl.setLeft("");
29071 this.bodyEl.show();
29075 * Set the tooltip for the tab.
29076 * @param {String} tooltip The tab's tooltip
29078 setTooltip : function(text){
29079 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29080 this.textEl.dom.qtip = text;
29081 this.textEl.dom.removeAttribute('title');
29083 this.textEl.dom.title = text;
29087 onTabClick : function(e){
29088 e.preventDefault();
29089 this.tabPanel.activate(this.id);
29092 onTabMouseDown : function(e){
29093 e.preventDefault();
29094 this.tabPanel.activate(this.id);
29097 getWidth : function(){
29098 return this.inner.getWidth();
29101 setWidth : function(width){
29102 var iwidth = width - this.pnode.getPadding("lr");
29103 this.inner.setWidth(iwidth);
29104 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29105 this.pnode.setWidth(width);
29109 * Show or hide the tab
29110 * @param {Boolean} hidden True to hide or false to show.
29112 setHidden : function(hidden){
29113 this.hidden = hidden;
29114 this.pnode.setStyle("display", hidden ? "none" : "");
29118 * Returns true if this tab is "hidden"
29119 * @return {Boolean}
29121 isHidden : function(){
29122 return this.hidden;
29126 * Returns the text for this tab
29129 getText : function(){
29133 autoSize : function(){
29134 //this.el.beginMeasure();
29135 this.textEl.setWidth(1);
29137 * #2804 [new] Tabs in Roojs
29138 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29140 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29141 //this.el.endMeasure();
29145 * Sets the text for the tab (Note: this also sets the tooltip text)
29146 * @param {String} text The tab's text and tooltip
29148 setText : function(text){
29150 this.textEl.update(text);
29151 this.setTooltip(text);
29152 if(!this.tabPanel.resizeTabs){
29157 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29159 activate : function(){
29160 this.tabPanel.activate(this.id);
29164 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29166 disable : function(){
29167 if(this.tabPanel.active != this){
29168 this.disabled = true;
29169 this.pnode.addClass("disabled");
29174 * Enables this TabPanelItem if it was previously disabled.
29176 enable : function(){
29177 this.disabled = false;
29178 this.pnode.removeClass("disabled");
29182 * Sets the content for this TabPanelItem.
29183 * @param {String} content The content
29184 * @param {Boolean} loadScripts true to look for and load scripts
29186 setContent : function(content, loadScripts){
29187 this.bodyEl.update(content, loadScripts);
29191 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29192 * @return {Roo.UpdateManager} The UpdateManager
29194 getUpdateManager : function(){
29195 return this.bodyEl.getUpdateManager();
29199 * Set a URL to be used to load the content for this TabPanelItem.
29200 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29201 * @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)
29202 * @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)
29203 * @return {Roo.UpdateManager} The UpdateManager
29205 setUrl : function(url, params, loadOnce){
29206 if(this.refreshDelegate){
29207 this.un('activate', this.refreshDelegate);
29209 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29210 this.on("activate", this.refreshDelegate);
29211 return this.bodyEl.getUpdateManager();
29215 _handleRefresh : function(url, params, loadOnce){
29216 if(!loadOnce || !this.loaded){
29217 var updater = this.bodyEl.getUpdateManager();
29218 updater.update(url, params, this._setLoaded.createDelegate(this));
29223 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29224 * Will fail silently if the setUrl method has not been called.
29225 * This does not activate the panel, just updates its content.
29227 refresh : function(){
29228 if(this.refreshDelegate){
29229 this.loaded = false;
29230 this.refreshDelegate();
29235 _setLoaded : function(){
29236 this.loaded = true;
29240 closeClick : function(e){
29243 this.fireEvent("beforeclose", this, o);
29244 if(o.cancel !== true){
29245 this.tabPanel.removeTab(this.id);
29249 * The text displayed in the tooltip for the close icon.
29252 closeText : "Close this tab"
29256 Roo.TabPanel.prototype.createStrip = function(container){
29257 var strip = document.createElement("div");
29258 strip.className = "x-tabs-wrap";
29259 container.appendChild(strip);
29263 Roo.TabPanel.prototype.createStripList = function(strip){
29264 // div wrapper for retard IE
29265 // returns the "tr" element.
29266 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29267 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29268 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29269 return strip.firstChild.firstChild.firstChild.firstChild;
29272 Roo.TabPanel.prototype.createBody = function(container){
29273 var body = document.createElement("div");
29274 Roo.id(body, "tab-body");
29275 Roo.fly(body).addClass("x-tabs-body");
29276 container.appendChild(body);
29280 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29281 var body = Roo.getDom(id);
29283 body = document.createElement("div");
29286 Roo.fly(body).addClass("x-tabs-item-body");
29287 bodyEl.insertBefore(body, bodyEl.firstChild);
29291 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29292 var td = document.createElement("td");
29293 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29294 //stripEl.appendChild(td);
29296 td.className = "x-tabs-closable";
29297 if(!this.closeTpl){
29298 this.closeTpl = new Roo.Template(
29299 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29300 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29301 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29304 var el = this.closeTpl.overwrite(td, {"text": text});
29305 var close = el.getElementsByTagName("div")[0];
29306 var inner = el.getElementsByTagName("em")[0];
29307 return {"el": el, "close": close, "inner": inner};
29310 this.tabTpl = new Roo.Template(
29311 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29312 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29315 var el = this.tabTpl.overwrite(td, {"text": text});
29316 var inner = el.getElementsByTagName("em")[0];
29317 return {"el": el, "inner": inner};
29321 * Ext JS Library 1.1.1
29322 * Copyright(c) 2006-2007, Ext JS, LLC.
29324 * Originally Released Under LGPL - original licence link has changed is not relivant.
29327 * <script type="text/javascript">
29331 * @class Roo.Button
29332 * @extends Roo.util.Observable
29333 * Simple Button class
29334 * @cfg {String} text The button text
29335 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29336 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29337 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29338 * @cfg {Object} scope The scope of the handler
29339 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29340 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29341 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29342 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29343 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29344 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29345 applies if enableToggle = true)
29346 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29347 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29348 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29350 * Create a new button
29351 * @param {Object} config The config object
29353 Roo.Button = function(renderTo, config)
29357 renderTo = config.renderTo || false;
29360 Roo.apply(this, config);
29364 * Fires when this button is clicked
29365 * @param {Button} this
29366 * @param {EventObject} e The click event
29371 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29372 * @param {Button} this
29373 * @param {Boolean} pressed
29378 * Fires when the mouse hovers over the button
29379 * @param {Button} this
29380 * @param {Event} e The event object
29382 'mouseover' : true,
29385 * Fires when the mouse exits the button
29386 * @param {Button} this
29387 * @param {Event} e The event object
29392 * Fires when the button is rendered
29393 * @param {Button} this
29398 this.menu = Roo.menu.MenuMgr.get(this.menu);
29400 // register listeners first!! - so render can be captured..
29401 Roo.util.Observable.call(this);
29403 this.render(renderTo);
29409 Roo.extend(Roo.Button, Roo.util.Observable, {
29415 * Read-only. True if this button is hidden
29420 * Read-only. True if this button is disabled
29425 * Read-only. True if this button is pressed (only if enableToggle = true)
29431 * @cfg {Number} tabIndex
29432 * The DOM tabIndex for this button (defaults to undefined)
29434 tabIndex : undefined,
29437 * @cfg {Boolean} enableToggle
29438 * True to enable pressed/not pressed toggling (defaults to false)
29440 enableToggle: false,
29442 * @cfg {Mixed} menu
29443 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29447 * @cfg {String} menuAlign
29448 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29450 menuAlign : "tl-bl?",
29453 * @cfg {String} iconCls
29454 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29456 iconCls : undefined,
29458 * @cfg {String} type
29459 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29464 menuClassTarget: 'tr',
29467 * @cfg {String} clickEvent
29468 * The type of event to map to the button's event handler (defaults to 'click')
29470 clickEvent : 'click',
29473 * @cfg {Boolean} handleMouseEvents
29474 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29476 handleMouseEvents : true,
29479 * @cfg {String} tooltipType
29480 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29482 tooltipType : 'qtip',
29485 * @cfg {String} cls
29486 * A CSS class to apply to the button's main element.
29490 * @cfg {Roo.Template} template (Optional)
29491 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29492 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29493 * require code modifications if required elements (e.g. a button) aren't present.
29497 render : function(renderTo){
29499 if(this.hideParent){
29500 this.parentEl = Roo.get(renderTo);
29502 if(!this.dhconfig){
29503 if(!this.template){
29504 if(!Roo.Button.buttonTemplate){
29505 // hideous table template
29506 Roo.Button.buttonTemplate = new Roo.Template(
29507 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29508 '<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>',
29509 "</tr></tbody></table>");
29511 this.template = Roo.Button.buttonTemplate;
29513 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29514 var btnEl = btn.child("button:first");
29515 btnEl.on('focus', this.onFocus, this);
29516 btnEl.on('blur', this.onBlur, this);
29518 btn.addClass(this.cls);
29521 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29524 btnEl.addClass(this.iconCls);
29526 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29529 if(this.tabIndex !== undefined){
29530 btnEl.dom.tabIndex = this.tabIndex;
29533 if(typeof this.tooltip == 'object'){
29534 Roo.QuickTips.tips(Roo.apply({
29538 btnEl.dom[this.tooltipType] = this.tooltip;
29542 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29546 this.el.dom.id = this.el.id = this.id;
29549 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29550 this.menu.on("show", this.onMenuShow, this);
29551 this.menu.on("hide", this.onMenuHide, this);
29553 btn.addClass("x-btn");
29554 if(Roo.isIE && !Roo.isIE7){
29555 this.autoWidth.defer(1, this);
29559 if(this.handleMouseEvents){
29560 btn.on("mouseover", this.onMouseOver, this);
29561 btn.on("mouseout", this.onMouseOut, this);
29562 btn.on("mousedown", this.onMouseDown, this);
29564 btn.on(this.clickEvent, this.onClick, this);
29565 //btn.on("mouseup", this.onMouseUp, this);
29572 Roo.ButtonToggleMgr.register(this);
29574 this.el.addClass("x-btn-pressed");
29577 var repeater = new Roo.util.ClickRepeater(btn,
29578 typeof this.repeat == "object" ? this.repeat : {}
29580 repeater.on("click", this.onClick, this);
29583 this.fireEvent('render', this);
29587 * Returns the button's underlying element
29588 * @return {Roo.Element} The element
29590 getEl : function(){
29595 * Destroys this Button and removes any listeners.
29597 destroy : function(){
29598 Roo.ButtonToggleMgr.unregister(this);
29599 this.el.removeAllListeners();
29600 this.purgeListeners();
29605 autoWidth : function(){
29607 this.el.setWidth("auto");
29608 if(Roo.isIE7 && Roo.isStrict){
29609 var ib = this.el.child('button');
29610 if(ib && ib.getWidth() > 20){
29612 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29617 this.el.beginMeasure();
29619 if(this.el.getWidth() < this.minWidth){
29620 this.el.setWidth(this.minWidth);
29623 this.el.endMeasure();
29630 * Assigns this button's click handler
29631 * @param {Function} handler The function to call when the button is clicked
29632 * @param {Object} scope (optional) Scope for the function passed in
29634 setHandler : function(handler, scope){
29635 this.handler = handler;
29636 this.scope = scope;
29640 * Sets this button's text
29641 * @param {String} text The button text
29643 setText : function(text){
29646 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29652 * Gets the text for this button
29653 * @return {String} The button text
29655 getText : function(){
29663 this.hidden = false;
29665 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29673 this.hidden = true;
29675 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29680 * Convenience function for boolean show/hide
29681 * @param {Boolean} visible True to show, false to hide
29683 setVisible: function(visible){
29692 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29693 * @param {Boolean} state (optional) Force a particular state
29695 toggle : function(state){
29696 state = state === undefined ? !this.pressed : state;
29697 if(state != this.pressed){
29699 this.el.addClass("x-btn-pressed");
29700 this.pressed = true;
29701 this.fireEvent("toggle", this, true);
29703 this.el.removeClass("x-btn-pressed");
29704 this.pressed = false;
29705 this.fireEvent("toggle", this, false);
29707 if(this.toggleHandler){
29708 this.toggleHandler.call(this.scope || this, this, state);
29716 focus : function(){
29717 this.el.child('button:first').focus();
29721 * Disable this button
29723 disable : function(){
29725 this.el.addClass("x-btn-disabled");
29727 this.disabled = true;
29731 * Enable this button
29733 enable : function(){
29735 this.el.removeClass("x-btn-disabled");
29737 this.disabled = false;
29741 * Convenience function for boolean enable/disable
29742 * @param {Boolean} enabled True to enable, false to disable
29744 setDisabled : function(v){
29745 this[v !== true ? "enable" : "disable"]();
29749 onClick : function(e)
29752 e.preventDefault();
29757 if(!this.disabled){
29758 if(this.enableToggle){
29761 if(this.menu && !this.menu.isVisible()){
29762 this.menu.show(this.el, this.menuAlign);
29764 this.fireEvent("click", this, e);
29766 this.el.removeClass("x-btn-over");
29767 this.handler.call(this.scope || this, this, e);
29772 onMouseOver : function(e){
29773 if(!this.disabled){
29774 this.el.addClass("x-btn-over");
29775 this.fireEvent('mouseover', this, e);
29779 onMouseOut : function(e){
29780 if(!e.within(this.el, true)){
29781 this.el.removeClass("x-btn-over");
29782 this.fireEvent('mouseout', this, e);
29786 onFocus : function(e){
29787 if(!this.disabled){
29788 this.el.addClass("x-btn-focus");
29792 onBlur : function(e){
29793 this.el.removeClass("x-btn-focus");
29796 onMouseDown : function(e){
29797 if(!this.disabled && e.button == 0){
29798 this.el.addClass("x-btn-click");
29799 Roo.get(document).on('mouseup', this.onMouseUp, this);
29803 onMouseUp : function(e){
29805 this.el.removeClass("x-btn-click");
29806 Roo.get(document).un('mouseup', this.onMouseUp, this);
29810 onMenuShow : function(e){
29811 this.el.addClass("x-btn-menu-active");
29814 onMenuHide : function(e){
29815 this.el.removeClass("x-btn-menu-active");
29819 // Private utility class used by Button
29820 Roo.ButtonToggleMgr = function(){
29823 function toggleGroup(btn, state){
29825 var g = groups[btn.toggleGroup];
29826 for(var i = 0, l = g.length; i < l; i++){
29828 g[i].toggle(false);
29835 register : function(btn){
29836 if(!btn.toggleGroup){
29839 var g = groups[btn.toggleGroup];
29841 g = groups[btn.toggleGroup] = [];
29844 btn.on("toggle", toggleGroup);
29847 unregister : function(btn){
29848 if(!btn.toggleGroup){
29851 var g = groups[btn.toggleGroup];
29854 btn.un("toggle", toggleGroup);
29860 * Ext JS Library 1.1.1
29861 * Copyright(c) 2006-2007, Ext JS, LLC.
29863 * Originally Released Under LGPL - original licence link has changed is not relivant.
29866 * <script type="text/javascript">
29870 * @class Roo.SplitButton
29871 * @extends Roo.Button
29872 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29873 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29874 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29875 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29876 * @cfg {String} arrowTooltip The title attribute of the arrow
29878 * Create a new menu button
29879 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29880 * @param {Object} config The config object
29882 Roo.SplitButton = function(renderTo, config){
29883 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29885 * @event arrowclick
29886 * Fires when this button's arrow is clicked
29887 * @param {SplitButton} this
29888 * @param {EventObject} e The click event
29890 this.addEvents({"arrowclick":true});
29893 Roo.extend(Roo.SplitButton, Roo.Button, {
29894 render : function(renderTo){
29895 // this is one sweet looking template!
29896 var tpl = new Roo.Template(
29897 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29898 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29899 '<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>',
29900 "</tbody></table></td><td>",
29901 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29902 '<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>',
29903 "</tbody></table></td></tr></table>"
29905 var btn = tpl.append(renderTo, [this.text, this.type], true);
29906 var btnEl = btn.child("button");
29908 btn.addClass(this.cls);
29911 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29914 btnEl.addClass(this.iconCls);
29916 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29920 if(this.handleMouseEvents){
29921 btn.on("mouseover", this.onMouseOver, this);
29922 btn.on("mouseout", this.onMouseOut, this);
29923 btn.on("mousedown", this.onMouseDown, this);
29924 btn.on("mouseup", this.onMouseUp, this);
29926 btn.on(this.clickEvent, this.onClick, this);
29928 if(typeof this.tooltip == 'object'){
29929 Roo.QuickTips.tips(Roo.apply({
29933 btnEl.dom[this.tooltipType] = this.tooltip;
29936 if(this.arrowTooltip){
29937 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29946 this.el.addClass("x-btn-pressed");
29948 if(Roo.isIE && !Roo.isIE7){
29949 this.autoWidth.defer(1, this);
29954 this.menu.on("show", this.onMenuShow, this);
29955 this.menu.on("hide", this.onMenuHide, this);
29957 this.fireEvent('render', this);
29961 autoWidth : function(){
29963 var tbl = this.el.child("table:first");
29964 var tbl2 = this.el.child("table:last");
29965 this.el.setWidth("auto");
29966 tbl.setWidth("auto");
29967 if(Roo.isIE7 && Roo.isStrict){
29968 var ib = this.el.child('button:first');
29969 if(ib && ib.getWidth() > 20){
29971 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29976 this.el.beginMeasure();
29978 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29979 tbl.setWidth(this.minWidth-tbl2.getWidth());
29982 this.el.endMeasure();
29985 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29989 * Sets this button's click handler
29990 * @param {Function} handler The function to call when the button is clicked
29991 * @param {Object} scope (optional) Scope for the function passed above
29993 setHandler : function(handler, scope){
29994 this.handler = handler;
29995 this.scope = scope;
29999 * Sets this button's arrow click handler
30000 * @param {Function} handler The function to call when the arrow is clicked
30001 * @param {Object} scope (optional) Scope for the function passed above
30003 setArrowHandler : function(handler, scope){
30004 this.arrowHandler = handler;
30005 this.scope = scope;
30011 focus : function(){
30013 this.el.child("button:first").focus();
30018 onClick : function(e){
30019 e.preventDefault();
30020 if(!this.disabled){
30021 if(e.getTarget(".x-btn-menu-arrow-wrap")){
30022 if(this.menu && !this.menu.isVisible()){
30023 this.menu.show(this.el, this.menuAlign);
30025 this.fireEvent("arrowclick", this, e);
30026 if(this.arrowHandler){
30027 this.arrowHandler.call(this.scope || this, this, e);
30030 this.fireEvent("click", this, e);
30032 this.handler.call(this.scope || this, this, e);
30038 onMouseDown : function(e){
30039 if(!this.disabled){
30040 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30044 onMouseUp : function(e){
30045 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30050 // backwards compat
30051 Roo.MenuButton = Roo.SplitButton;/*
30053 * Ext JS Library 1.1.1
30054 * Copyright(c) 2006-2007, Ext JS, LLC.
30056 * Originally Released Under LGPL - original licence link has changed is not relivant.
30059 * <script type="text/javascript">
30063 * @class Roo.Toolbar
30064 * Basic Toolbar class.
30066 * Creates a new Toolbar
30067 * @param {Object} container The config object
30069 Roo.Toolbar = function(container, buttons, config)
30071 /// old consturctor format still supported..
30072 if(container instanceof Array){ // omit the container for later rendering
30073 buttons = container;
30077 if (typeof(container) == 'object' && container.xtype) {
30078 config = container;
30079 container = config.container;
30080 buttons = config.buttons || []; // not really - use items!!
30083 if (config && config.items) {
30084 xitems = config.items;
30085 delete config.items;
30087 Roo.apply(this, config);
30088 this.buttons = buttons;
30091 this.render(container);
30093 this.xitems = xitems;
30094 Roo.each(xitems, function(b) {
30100 Roo.Toolbar.prototype = {
30102 * @cfg {Array} items
30103 * array of button configs or elements to add (will be converted to a MixedCollection)
30107 * @cfg {String/HTMLElement/Element} container
30108 * The id or element that will contain the toolbar
30111 render : function(ct){
30112 this.el = Roo.get(ct);
30114 this.el.addClass(this.cls);
30116 // using a table allows for vertical alignment
30117 // 100% width is needed by Safari...
30118 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30119 this.tr = this.el.child("tr", true);
30121 this.items = new Roo.util.MixedCollection(false, function(o){
30122 return o.id || ("item" + (++autoId));
30125 this.add.apply(this, this.buttons);
30126 delete this.buttons;
30131 * Adds element(s) to the toolbar -- this function takes a variable number of
30132 * arguments of mixed type and adds them to the toolbar.
30133 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30135 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30136 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30137 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30138 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30139 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30140 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30141 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30142 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30143 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30145 * @param {Mixed} arg2
30146 * @param {Mixed} etc.
30149 var a = arguments, l = a.length;
30150 for(var i = 0; i < l; i++){
30155 _add : function(el) {
30158 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30161 if (el.applyTo){ // some kind of form field
30162 return this.addField(el);
30164 if (el.render){ // some kind of Toolbar.Item
30165 return this.addItem(el);
30167 if (typeof el == "string"){ // string
30168 if(el == "separator" || el == "-"){
30169 return this.addSeparator();
30172 return this.addSpacer();
30175 return this.addFill();
30177 return this.addText(el);
30180 if(el.tagName){ // element
30181 return this.addElement(el);
30183 if(typeof el == "object"){ // must be button config?
30184 return this.addButton(el);
30186 // and now what?!?!
30192 * Add an Xtype element
30193 * @param {Object} xtype Xtype Object
30194 * @return {Object} created Object
30196 addxtype : function(e){
30197 return this.add(e);
30201 * Returns the Element for this toolbar.
30202 * @return {Roo.Element}
30204 getEl : function(){
30210 * @return {Roo.Toolbar.Item} The separator item
30212 addSeparator : function(){
30213 return this.addItem(new Roo.Toolbar.Separator());
30217 * Adds a spacer element
30218 * @return {Roo.Toolbar.Spacer} The spacer item
30220 addSpacer : function(){
30221 return this.addItem(new Roo.Toolbar.Spacer());
30225 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30226 * @return {Roo.Toolbar.Fill} The fill item
30228 addFill : function(){
30229 return this.addItem(new Roo.Toolbar.Fill());
30233 * Adds any standard HTML element to the toolbar
30234 * @param {String/HTMLElement/Element} el The element or id of the element to add
30235 * @return {Roo.Toolbar.Item} The element's item
30237 addElement : function(el){
30238 return this.addItem(new Roo.Toolbar.Item(el));
30241 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30242 * @type Roo.util.MixedCollection
30247 * Adds any Toolbar.Item or subclass
30248 * @param {Roo.Toolbar.Item} item
30249 * @return {Roo.Toolbar.Item} The item
30251 addItem : function(item){
30252 var td = this.nextBlock();
30254 this.items.add(item);
30259 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30260 * @param {Object/Array} config A button config or array of configs
30261 * @return {Roo.Toolbar.Button/Array}
30263 addButton : function(config){
30264 if(config instanceof Array){
30266 for(var i = 0, len = config.length; i < len; i++) {
30267 buttons.push(this.addButton(config[i]));
30272 if(!(config instanceof Roo.Toolbar.Button)){
30274 new Roo.Toolbar.SplitButton(config) :
30275 new Roo.Toolbar.Button(config);
30277 var td = this.nextBlock();
30284 * Adds text to the toolbar
30285 * @param {String} text The text to add
30286 * @return {Roo.Toolbar.Item} The element's item
30288 addText : function(text){
30289 return this.addItem(new Roo.Toolbar.TextItem(text));
30293 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30294 * @param {Number} index The index where the item is to be inserted
30295 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30296 * @return {Roo.Toolbar.Button/Item}
30298 insertButton : function(index, item){
30299 if(item instanceof Array){
30301 for(var i = 0, len = item.length; i < len; i++) {
30302 buttons.push(this.insertButton(index + i, item[i]));
30306 if (!(item instanceof Roo.Toolbar.Button)){
30307 item = new Roo.Toolbar.Button(item);
30309 var td = document.createElement("td");
30310 this.tr.insertBefore(td, this.tr.childNodes[index]);
30312 this.items.insert(index, item);
30317 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30318 * @param {Object} config
30319 * @return {Roo.Toolbar.Item} The element's item
30321 addDom : function(config, returnEl){
30322 var td = this.nextBlock();
30323 Roo.DomHelper.overwrite(td, config);
30324 var ti = new Roo.Toolbar.Item(td.firstChild);
30326 this.items.add(ti);
30331 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30332 * @type Roo.util.MixedCollection
30337 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30338 * Note: the field should not have been rendered yet. For a field that has already been
30339 * rendered, use {@link #addElement}.
30340 * @param {Roo.form.Field} field
30341 * @return {Roo.ToolbarItem}
30345 addField : function(field) {
30346 if (!this.fields) {
30348 this.fields = new Roo.util.MixedCollection(false, function(o){
30349 return o.id || ("item" + (++autoId));
30354 var td = this.nextBlock();
30356 var ti = new Roo.Toolbar.Item(td.firstChild);
30358 this.items.add(ti);
30359 this.fields.add(field);
30370 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30371 this.el.child('div').hide();
30379 this.el.child('div').show();
30383 nextBlock : function(){
30384 var td = document.createElement("td");
30385 this.tr.appendChild(td);
30390 destroy : function(){
30391 if(this.items){ // rendered?
30392 Roo.destroy.apply(Roo, this.items.items);
30394 if(this.fields){ // rendered?
30395 Roo.destroy.apply(Roo, this.fields.items);
30397 Roo.Element.uncache(this.el, this.tr);
30402 * @class Roo.Toolbar.Item
30403 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30405 * Creates a new Item
30406 * @param {HTMLElement} el
30408 Roo.Toolbar.Item = function(el){
30410 if (typeof (el.xtype) != 'undefined') {
30415 this.el = Roo.getDom(el);
30416 this.id = Roo.id(this.el);
30417 this.hidden = false;
30422 * Fires when the button is rendered
30423 * @param {Button} this
30427 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30429 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30430 //Roo.Toolbar.Item.prototype = {
30433 * Get this item's HTML Element
30434 * @return {HTMLElement}
30436 getEl : function(){
30441 render : function(td){
30444 td.appendChild(this.el);
30446 this.fireEvent('render', this);
30450 * Removes and destroys this item.
30452 destroy : function(){
30453 this.td.parentNode.removeChild(this.td);
30460 this.hidden = false;
30461 this.td.style.display = "";
30468 this.hidden = true;
30469 this.td.style.display = "none";
30473 * Convenience function for boolean show/hide.
30474 * @param {Boolean} visible true to show/false to hide
30476 setVisible: function(visible){
30485 * Try to focus this item.
30487 focus : function(){
30488 Roo.fly(this.el).focus();
30492 * Disables this item.
30494 disable : function(){
30495 Roo.fly(this.td).addClass("x-item-disabled");
30496 this.disabled = true;
30497 this.el.disabled = true;
30501 * Enables this item.
30503 enable : function(){
30504 Roo.fly(this.td).removeClass("x-item-disabled");
30505 this.disabled = false;
30506 this.el.disabled = false;
30512 * @class Roo.Toolbar.Separator
30513 * @extends Roo.Toolbar.Item
30514 * A simple toolbar separator class
30516 * Creates a new Separator
30518 Roo.Toolbar.Separator = function(cfg){
30520 var s = document.createElement("span");
30521 s.className = "ytb-sep";
30526 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30528 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30529 enable:Roo.emptyFn,
30530 disable:Roo.emptyFn,
30535 * @class Roo.Toolbar.Spacer
30536 * @extends Roo.Toolbar.Item
30537 * A simple element that adds extra horizontal space to a toolbar.
30539 * Creates a new Spacer
30541 Roo.Toolbar.Spacer = function(cfg){
30542 var s = document.createElement("div");
30543 s.className = "ytb-spacer";
30547 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30549 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30550 enable:Roo.emptyFn,
30551 disable:Roo.emptyFn,
30556 * @class Roo.Toolbar.Fill
30557 * @extends Roo.Toolbar.Spacer
30558 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30560 * Creates a new Spacer
30562 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30564 render : function(td){
30565 td.style.width = '100%';
30566 Roo.Toolbar.Fill.superclass.render.call(this, td);
30571 * @class Roo.Toolbar.TextItem
30572 * @extends Roo.Toolbar.Item
30573 * A simple class that renders text directly into a toolbar.
30575 * Creates a new TextItem
30576 * @cfg {string} text
30578 Roo.Toolbar.TextItem = function(cfg){
30579 var text = cfg || "";
30580 if (typeof(cfg) == 'object') {
30581 text = cfg.text || "";
30585 var s = document.createElement("span");
30586 s.className = "ytb-text";
30587 s.innerHTML = text;
30592 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30594 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30597 enable:Roo.emptyFn,
30598 disable:Roo.emptyFn,
30603 * @class Roo.Toolbar.Button
30604 * @extends Roo.Button
30605 * A button that renders into a toolbar.
30607 * Creates a new Button
30608 * @param {Object} config A standard {@link Roo.Button} config object
30610 Roo.Toolbar.Button = function(config){
30611 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30613 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30614 render : function(td){
30616 Roo.Toolbar.Button.superclass.render.call(this, td);
30620 * Removes and destroys this button
30622 destroy : function(){
30623 Roo.Toolbar.Button.superclass.destroy.call(this);
30624 this.td.parentNode.removeChild(this.td);
30628 * Shows this button
30631 this.hidden = false;
30632 this.td.style.display = "";
30636 * Hides this button
30639 this.hidden = true;
30640 this.td.style.display = "none";
30644 * Disables this item
30646 disable : function(){
30647 Roo.fly(this.td).addClass("x-item-disabled");
30648 this.disabled = true;
30652 * Enables this item
30654 enable : function(){
30655 Roo.fly(this.td).removeClass("x-item-disabled");
30656 this.disabled = false;
30659 // backwards compat
30660 Roo.ToolbarButton = Roo.Toolbar.Button;
30663 * @class Roo.Toolbar.SplitButton
30664 * @extends Roo.SplitButton
30665 * A menu button that renders into a toolbar.
30667 * Creates a new SplitButton
30668 * @param {Object} config A standard {@link Roo.SplitButton} config object
30670 Roo.Toolbar.SplitButton = function(config){
30671 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30673 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30674 render : function(td){
30676 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30680 * Removes and destroys this button
30682 destroy : function(){
30683 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30684 this.td.parentNode.removeChild(this.td);
30688 * Shows this button
30691 this.hidden = false;
30692 this.td.style.display = "";
30696 * Hides this button
30699 this.hidden = true;
30700 this.td.style.display = "none";
30704 // backwards compat
30705 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30707 * Ext JS Library 1.1.1
30708 * Copyright(c) 2006-2007, Ext JS, LLC.
30710 * Originally Released Under LGPL - original licence link has changed is not relivant.
30713 * <script type="text/javascript">
30717 * @class Roo.PagingToolbar
30718 * @extends Roo.Toolbar
30719 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30721 * Create a new PagingToolbar
30722 * @param {Object} config The config object
30724 Roo.PagingToolbar = function(el, ds, config)
30726 // old args format still supported... - xtype is prefered..
30727 if (typeof(el) == 'object' && el.xtype) {
30728 // created from xtype...
30730 ds = el.dataSource;
30731 el = config.container;
30734 if (config.items) {
30735 items = config.items;
30739 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30742 this.renderButtons(this.el);
30745 // supprot items array.
30747 Roo.each(items, function(e) {
30748 this.add(Roo.factory(e));
30753 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30755 * @cfg {Roo.data.Store} dataSource
30756 * The underlying data store providing the paged data
30759 * @cfg {String/HTMLElement/Element} container
30760 * container The id or element that will contain the toolbar
30763 * @cfg {Boolean} displayInfo
30764 * True to display the displayMsg (defaults to false)
30767 * @cfg {Number} pageSize
30768 * The number of records to display per page (defaults to 20)
30772 * @cfg {String} displayMsg
30773 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30775 displayMsg : 'Displaying {0} - {1} of {2}',
30777 * @cfg {String} emptyMsg
30778 * The message to display when no records are found (defaults to "No data to display")
30780 emptyMsg : 'No data to display',
30782 * Customizable piece of the default paging text (defaults to "Page")
30785 beforePageText : "Page",
30787 * Customizable piece of the default paging text (defaults to "of %0")
30790 afterPageText : "of {0}",
30792 * Customizable piece of the default paging text (defaults to "First Page")
30795 firstText : "First Page",
30797 * Customizable piece of the default paging text (defaults to "Previous Page")
30800 prevText : "Previous Page",
30802 * Customizable piece of the default paging text (defaults to "Next Page")
30805 nextText : "Next Page",
30807 * Customizable piece of the default paging text (defaults to "Last Page")
30810 lastText : "Last Page",
30812 * Customizable piece of the default paging text (defaults to "Refresh")
30815 refreshText : "Refresh",
30818 renderButtons : function(el){
30819 Roo.PagingToolbar.superclass.render.call(this, el);
30820 this.first = this.addButton({
30821 tooltip: this.firstText,
30822 cls: "x-btn-icon x-grid-page-first",
30824 handler: this.onClick.createDelegate(this, ["first"])
30826 this.prev = this.addButton({
30827 tooltip: this.prevText,
30828 cls: "x-btn-icon x-grid-page-prev",
30830 handler: this.onClick.createDelegate(this, ["prev"])
30832 //this.addSeparator();
30833 this.add(this.beforePageText);
30834 this.field = Roo.get(this.addDom({
30839 cls: "x-grid-page-number"
30841 this.field.on("keydown", this.onPagingKeydown, this);
30842 this.field.on("focus", function(){this.dom.select();});
30843 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30844 this.field.setHeight(18);
30845 //this.addSeparator();
30846 this.next = this.addButton({
30847 tooltip: this.nextText,
30848 cls: "x-btn-icon x-grid-page-next",
30850 handler: this.onClick.createDelegate(this, ["next"])
30852 this.last = this.addButton({
30853 tooltip: this.lastText,
30854 cls: "x-btn-icon x-grid-page-last",
30856 handler: this.onClick.createDelegate(this, ["last"])
30858 //this.addSeparator();
30859 this.loading = this.addButton({
30860 tooltip: this.refreshText,
30861 cls: "x-btn-icon x-grid-loading",
30862 handler: this.onClick.createDelegate(this, ["refresh"])
30865 if(this.displayInfo){
30866 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30871 updateInfo : function(){
30872 if(this.displayEl){
30873 var count = this.ds.getCount();
30874 var msg = count == 0 ?
30878 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30880 this.displayEl.update(msg);
30885 onLoad : function(ds, r, o){
30886 this.cursor = o.params ? o.params.start : 0;
30887 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30889 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30890 this.field.dom.value = ap;
30891 this.first.setDisabled(ap == 1);
30892 this.prev.setDisabled(ap == 1);
30893 this.next.setDisabled(ap == ps);
30894 this.last.setDisabled(ap == ps);
30895 this.loading.enable();
30900 getPageData : function(){
30901 var total = this.ds.getTotalCount();
30904 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30905 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30910 onLoadError : function(){
30911 this.loading.enable();
30915 onPagingKeydown : function(e){
30916 var k = e.getKey();
30917 var d = this.getPageData();
30919 var v = this.field.dom.value, pageNum;
30920 if(!v || isNaN(pageNum = parseInt(v, 10))){
30921 this.field.dom.value = d.activePage;
30924 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30925 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30928 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))
30930 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30931 this.field.dom.value = pageNum;
30932 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30935 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30937 var v = this.field.dom.value, pageNum;
30938 var increment = (e.shiftKey) ? 10 : 1;
30939 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30942 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30943 this.field.dom.value = d.activePage;
30946 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30948 this.field.dom.value = parseInt(v, 10) + increment;
30949 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30950 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30957 beforeLoad : function(){
30959 this.loading.disable();
30964 onClick : function(which){
30968 ds.load({params:{start: 0, limit: this.pageSize}});
30971 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30974 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30977 var total = ds.getTotalCount();
30978 var extra = total % this.pageSize;
30979 var lastStart = extra ? (total - extra) : total-this.pageSize;
30980 ds.load({params:{start: lastStart, limit: this.pageSize}});
30983 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30989 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30990 * @param {Roo.data.Store} store The data store to unbind
30992 unbind : function(ds){
30993 ds.un("beforeload", this.beforeLoad, this);
30994 ds.un("load", this.onLoad, this);
30995 ds.un("loadexception", this.onLoadError, this);
30996 ds.un("remove", this.updateInfo, this);
30997 ds.un("add", this.updateInfo, this);
30998 this.ds = undefined;
31002 * Binds the paging toolbar to the specified {@link Roo.data.Store}
31003 * @param {Roo.data.Store} store The data store to bind
31005 bind : function(ds){
31006 ds.on("beforeload", this.beforeLoad, this);
31007 ds.on("load", this.onLoad, this);
31008 ds.on("loadexception", this.onLoadError, this);
31009 ds.on("remove", this.updateInfo, this);
31010 ds.on("add", this.updateInfo, this);
31015 * Ext JS Library 1.1.1
31016 * Copyright(c) 2006-2007, Ext JS, LLC.
31018 * Originally Released Under LGPL - original licence link has changed is not relivant.
31021 * <script type="text/javascript">
31025 * @class Roo.Resizable
31026 * @extends Roo.util.Observable
31027 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
31028 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
31029 * 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
31030 * the element will be wrapped for you automatically.</p>
31031 * <p>Here is the list of valid resize handles:</p>
31034 ------ -------------------
31043 'hd' horizontal drag
31046 * <p>Here's an example showing the creation of a typical Resizable:</p>
31048 var resizer = new Roo.Resizable("element-id", {
31056 resizer.on("resize", myHandler);
31058 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31059 * resizer.east.setDisplayed(false);</p>
31060 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31061 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31062 * resize operation's new size (defaults to [0, 0])
31063 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31064 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31065 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31066 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31067 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31068 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31069 * @cfg {Number} width The width of the element in pixels (defaults to null)
31070 * @cfg {Number} height The height of the element in pixels (defaults to null)
31071 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31072 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31073 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31074 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31075 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31076 * in favor of the handles config option (defaults to false)
31077 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31078 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31079 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31080 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31081 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31082 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31083 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31084 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31085 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31086 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31087 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31089 * Create a new resizable component
31090 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31091 * @param {Object} config configuration options
31093 Roo.Resizable = function(el, config)
31095 this.el = Roo.get(el);
31097 if(config && config.wrap){
31098 config.resizeChild = this.el;
31099 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31100 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31101 this.el.setStyle("overflow", "hidden");
31102 this.el.setPositioning(config.resizeChild.getPositioning());
31103 config.resizeChild.clearPositioning();
31104 if(!config.width || !config.height){
31105 var csize = config.resizeChild.getSize();
31106 this.el.setSize(csize.width, csize.height);
31108 if(config.pinned && !config.adjustments){
31109 config.adjustments = "auto";
31113 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31114 this.proxy.unselectable();
31115 this.proxy.enableDisplayMode('block');
31117 Roo.apply(this, config);
31120 this.disableTrackOver = true;
31121 this.el.addClass("x-resizable-pinned");
31123 // if the element isn't positioned, make it relative
31124 var position = this.el.getStyle("position");
31125 if(position != "absolute" && position != "fixed"){
31126 this.el.setStyle("position", "relative");
31128 if(!this.handles){ // no handles passed, must be legacy style
31129 this.handles = 's,e,se';
31130 if(this.multiDirectional){
31131 this.handles += ',n,w';
31134 if(this.handles == "all"){
31135 this.handles = "n s e w ne nw se sw";
31137 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31138 var ps = Roo.Resizable.positions;
31139 for(var i = 0, len = hs.length; i < len; i++){
31140 if(hs[i] && ps[hs[i]]){
31141 var pos = ps[hs[i]];
31142 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31146 this.corner = this.southeast;
31148 // updateBox = the box can move..
31149 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31150 this.updateBox = true;
31153 this.activeHandle = null;
31155 if(this.resizeChild){
31156 if(typeof this.resizeChild == "boolean"){
31157 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31159 this.resizeChild = Roo.get(this.resizeChild, true);
31163 if(this.adjustments == "auto"){
31164 var rc = this.resizeChild;
31165 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31166 if(rc && (hw || hn)){
31167 rc.position("relative");
31168 rc.setLeft(hw ? hw.el.getWidth() : 0);
31169 rc.setTop(hn ? hn.el.getHeight() : 0);
31171 this.adjustments = [
31172 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31173 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31177 if(this.draggable){
31178 this.dd = this.dynamic ?
31179 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31180 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31186 * @event beforeresize
31187 * Fired before resize is allowed. Set enabled to false to cancel resize.
31188 * @param {Roo.Resizable} this
31189 * @param {Roo.EventObject} e The mousedown event
31191 "beforeresize" : true,
31194 * Fired a resizing.
31195 * @param {Roo.Resizable} this
31196 * @param {Number} x The new x position
31197 * @param {Number} y The new y position
31198 * @param {Number} w The new w width
31199 * @param {Number} h The new h hight
31200 * @param {Roo.EventObject} e The mouseup event
31205 * Fired after a resize.
31206 * @param {Roo.Resizable} this
31207 * @param {Number} width The new width
31208 * @param {Number} height The new height
31209 * @param {Roo.EventObject} e The mouseup event
31214 if(this.width !== null && this.height !== null){
31215 this.resizeTo(this.width, this.height);
31217 this.updateChildSize();
31220 this.el.dom.style.zoom = 1;
31222 Roo.Resizable.superclass.constructor.call(this);
31225 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31226 resizeChild : false,
31227 adjustments : [0, 0],
31237 multiDirectional : false,
31238 disableTrackOver : false,
31239 easing : 'easeOutStrong',
31240 widthIncrement : 0,
31241 heightIncrement : 0,
31245 preserveRatio : false,
31246 transparent: false,
31252 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31254 constrainTo: undefined,
31256 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31258 resizeRegion: undefined,
31262 * Perform a manual resize
31263 * @param {Number} width
31264 * @param {Number} height
31266 resizeTo : function(width, height){
31267 this.el.setSize(width, height);
31268 this.updateChildSize();
31269 this.fireEvent("resize", this, width, height, null);
31273 startSizing : function(e, handle){
31274 this.fireEvent("beforeresize", this, e);
31275 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31278 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31279 this.overlay.unselectable();
31280 this.overlay.enableDisplayMode("block");
31281 this.overlay.on("mousemove", this.onMouseMove, this);
31282 this.overlay.on("mouseup", this.onMouseUp, this);
31284 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31286 this.resizing = true;
31287 this.startBox = this.el.getBox();
31288 this.startPoint = e.getXY();
31289 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31290 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31292 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31293 this.overlay.show();
31295 if(this.constrainTo) {
31296 var ct = Roo.get(this.constrainTo);
31297 this.resizeRegion = ct.getRegion().adjust(
31298 ct.getFrameWidth('t'),
31299 ct.getFrameWidth('l'),
31300 -ct.getFrameWidth('b'),
31301 -ct.getFrameWidth('r')
31305 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31307 this.proxy.setBox(this.startBox);
31309 this.proxy.setStyle('visibility', 'visible');
31315 onMouseDown : function(handle, e){
31318 this.activeHandle = handle;
31319 this.startSizing(e, handle);
31324 onMouseUp : function(e){
31325 var size = this.resizeElement();
31326 this.resizing = false;
31328 this.overlay.hide();
31330 this.fireEvent("resize", this, size.width, size.height, e);
31334 updateChildSize : function(){
31336 if(this.resizeChild){
31338 var child = this.resizeChild;
31339 var adj = this.adjustments;
31340 if(el.dom.offsetWidth){
31341 var b = el.getSize(true);
31342 child.setSize(b.width+adj[0], b.height+adj[1]);
31344 // Second call here for IE
31345 // The first call enables instant resizing and
31346 // the second call corrects scroll bars if they
31349 setTimeout(function(){
31350 if(el.dom.offsetWidth){
31351 var b = el.getSize(true);
31352 child.setSize(b.width+adj[0], b.height+adj[1]);
31360 snap : function(value, inc, min){
31361 if(!inc || !value) {
31364 var newValue = value;
31365 var m = value % inc;
31368 newValue = value + (inc-m);
31370 newValue = value - m;
31373 return Math.max(min, newValue);
31377 resizeElement : function(){
31378 var box = this.proxy.getBox();
31379 if(this.updateBox){
31380 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31382 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31384 this.updateChildSize();
31392 constrain : function(v, diff, m, mx){
31395 }else if(v - diff > mx){
31402 onMouseMove : function(e){
31405 try{// try catch so if something goes wrong the user doesn't get hung
31407 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31411 //var curXY = this.startPoint;
31412 var curSize = this.curSize || this.startBox;
31413 var x = this.startBox.x, y = this.startBox.y;
31414 var ox = x, oy = y;
31415 var w = curSize.width, h = curSize.height;
31416 var ow = w, oh = h;
31417 var mw = this.minWidth, mh = this.minHeight;
31418 var mxw = this.maxWidth, mxh = this.maxHeight;
31419 var wi = this.widthIncrement;
31420 var hi = this.heightIncrement;
31422 var eventXY = e.getXY();
31423 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31424 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31426 var pos = this.activeHandle.position;
31431 w = Math.min(Math.max(mw, w), mxw);
31436 h = Math.min(Math.max(mh, h), mxh);
31441 w = Math.min(Math.max(mw, w), mxw);
31442 h = Math.min(Math.max(mh, h), mxh);
31445 diffY = this.constrain(h, diffY, mh, mxh);
31452 var adiffX = Math.abs(diffX);
31453 var sub = (adiffX % wi); // how much
31454 if (sub > (wi/2)) { // far enough to snap
31455 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31457 // remove difference..
31458 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31462 x = Math.max(this.minX, x);
31465 diffX = this.constrain(w, diffX, mw, mxw);
31471 w = Math.min(Math.max(mw, w), mxw);
31472 diffY = this.constrain(h, diffY, mh, mxh);
31477 diffX = this.constrain(w, diffX, mw, mxw);
31478 diffY = this.constrain(h, diffY, mh, mxh);
31485 diffX = this.constrain(w, diffX, mw, mxw);
31487 h = Math.min(Math.max(mh, h), mxh);
31493 var sw = this.snap(w, wi, mw);
31494 var sh = this.snap(h, hi, mh);
31495 if(sw != w || sh != h){
31518 if(this.preserveRatio){
31523 h = Math.min(Math.max(mh, h), mxh);
31528 w = Math.min(Math.max(mw, w), mxw);
31533 w = Math.min(Math.max(mw, w), mxw);
31539 w = Math.min(Math.max(mw, w), mxw);
31545 h = Math.min(Math.max(mh, h), mxh);
31553 h = Math.min(Math.max(mh, h), mxh);
31563 h = Math.min(Math.max(mh, h), mxh);
31571 if (pos == 'hdrag') {
31574 this.proxy.setBounds(x, y, w, h);
31576 this.resizeElement();
31580 this.fireEvent("resizing", this, x, y, w, h, e);
31584 handleOver : function(){
31586 this.el.addClass("x-resizable-over");
31591 handleOut : function(){
31592 if(!this.resizing){
31593 this.el.removeClass("x-resizable-over");
31598 * Returns the element this component is bound to.
31599 * @return {Roo.Element}
31601 getEl : function(){
31606 * Returns the resizeChild element (or null).
31607 * @return {Roo.Element}
31609 getResizeChild : function(){
31610 return this.resizeChild;
31612 groupHandler : function()
31617 * Destroys this resizable. If the element was wrapped and
31618 * removeEl is not true then the element remains.
31619 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31621 destroy : function(removeEl){
31622 this.proxy.remove();
31624 this.overlay.removeAllListeners();
31625 this.overlay.remove();
31627 var ps = Roo.Resizable.positions;
31629 if(typeof ps[k] != "function" && this[ps[k]]){
31630 var h = this[ps[k]];
31631 h.el.removeAllListeners();
31636 this.el.update("");
31643 // hash to map config positions to true positions
31644 Roo.Resizable.positions = {
31645 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31650 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31652 // only initialize the template if resizable is used
31653 var tpl = Roo.DomHelper.createTemplate(
31654 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31657 Roo.Resizable.Handle.prototype.tpl = tpl;
31659 this.position = pos;
31661 // show north drag fro topdra
31662 var handlepos = pos == 'hdrag' ? 'north' : pos;
31664 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31665 if (pos == 'hdrag') {
31666 this.el.setStyle('cursor', 'pointer');
31668 this.el.unselectable();
31670 this.el.setOpacity(0);
31672 this.el.on("mousedown", this.onMouseDown, this);
31673 if(!disableTrackOver){
31674 this.el.on("mouseover", this.onMouseOver, this);
31675 this.el.on("mouseout", this.onMouseOut, this);
31680 Roo.Resizable.Handle.prototype = {
31681 afterResize : function(rz){
31686 onMouseDown : function(e){
31687 this.rz.onMouseDown(this, e);
31690 onMouseOver : function(e){
31691 this.rz.handleOver(this, e);
31694 onMouseOut : function(e){
31695 this.rz.handleOut(this, e);
31699 * Ext JS Library 1.1.1
31700 * Copyright(c) 2006-2007, Ext JS, LLC.
31702 * Originally Released Under LGPL - original licence link has changed is not relivant.
31705 * <script type="text/javascript">
31709 * @class Roo.Editor
31710 * @extends Roo.Component
31711 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31713 * Create a new Editor
31714 * @param {Roo.form.Field} field The Field object (or descendant)
31715 * @param {Object} config The config object
31717 Roo.Editor = function(field, config){
31718 Roo.Editor.superclass.constructor.call(this, config);
31719 this.field = field;
31722 * @event beforestartedit
31723 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31724 * false from the handler of this event.
31725 * @param {Editor} this
31726 * @param {Roo.Element} boundEl The underlying element bound to this editor
31727 * @param {Mixed} value The field value being set
31729 "beforestartedit" : true,
31732 * Fires when this editor is displayed
31733 * @param {Roo.Element} boundEl The underlying element bound to this editor
31734 * @param {Mixed} value The starting field value
31736 "startedit" : true,
31738 * @event beforecomplete
31739 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31740 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31741 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31742 * event will not fire since no edit actually occurred.
31743 * @param {Editor} this
31744 * @param {Mixed} value The current field value
31745 * @param {Mixed} startValue The original field value
31747 "beforecomplete" : true,
31750 * Fires after editing is complete and any changed value has been written to the underlying field.
31751 * @param {Editor} this
31752 * @param {Mixed} value The current field value
31753 * @param {Mixed} startValue The original field value
31757 * @event specialkey
31758 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31759 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31760 * @param {Roo.form.Field} this
31761 * @param {Roo.EventObject} e The event object
31763 "specialkey" : true
31767 Roo.extend(Roo.Editor, Roo.Component, {
31769 * @cfg {Boolean/String} autosize
31770 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31771 * or "height" to adopt the height only (defaults to false)
31774 * @cfg {Boolean} revertInvalid
31775 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31776 * validation fails (defaults to true)
31779 * @cfg {Boolean} ignoreNoChange
31780 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31781 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31782 * will never be ignored.
31785 * @cfg {Boolean} hideEl
31786 * False to keep the bound element visible while the editor is displayed (defaults to true)
31789 * @cfg {Mixed} value
31790 * The data value of the underlying field (defaults to "")
31794 * @cfg {String} alignment
31795 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31799 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31800 * for bottom-right shadow (defaults to "frame")
31804 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31808 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31810 completeOnEnter : false,
31812 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31814 cancelOnEsc : false,
31816 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31821 onRender : function(ct, position){
31822 this.el = new Roo.Layer({
31823 shadow: this.shadow,
31829 constrain: this.constrain
31831 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31832 if(this.field.msgTarget != 'title'){
31833 this.field.msgTarget = 'qtip';
31835 this.field.render(this.el);
31837 this.field.el.dom.setAttribute('autocomplete', 'off');
31839 this.field.on("specialkey", this.onSpecialKey, this);
31840 if(this.swallowKeys){
31841 this.field.el.swallowEvent(['keydown','keypress']);
31844 this.field.on("blur", this.onBlur, this);
31845 if(this.field.grow){
31846 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31850 onSpecialKey : function(field, e)
31852 //Roo.log('editor onSpecialKey');
31853 if(this.completeOnEnter && e.getKey() == e.ENTER){
31855 this.completeEdit();
31858 // do not fire special key otherwise it might hide close the editor...
31859 if(e.getKey() == e.ENTER){
31862 if(this.cancelOnEsc && e.getKey() == e.ESC){
31866 this.fireEvent('specialkey', field, e);
31871 * Starts the editing process and shows the editor.
31872 * @param {String/HTMLElement/Element} el The element to edit
31873 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31874 * to the innerHTML of el.
31876 startEdit : function(el, value){
31878 this.completeEdit();
31880 this.boundEl = Roo.get(el);
31881 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31882 if(!this.rendered){
31883 this.render(this.parentEl || document.body);
31885 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31888 this.startValue = v;
31889 this.field.setValue(v);
31891 var sz = this.boundEl.getSize();
31892 switch(this.autoSize){
31894 this.setSize(sz.width, "");
31897 this.setSize("", sz.height);
31900 this.setSize(sz.width, sz.height);
31903 this.el.alignTo(this.boundEl, this.alignment);
31904 this.editing = true;
31906 Roo.QuickTips.disable();
31912 * Sets the height and width of this editor.
31913 * @param {Number} width The new width
31914 * @param {Number} height The new height
31916 setSize : function(w, h){
31917 this.field.setSize(w, h);
31924 * Realigns the editor to the bound field based on the current alignment config value.
31926 realign : function(){
31927 this.el.alignTo(this.boundEl, this.alignment);
31931 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31932 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31934 completeEdit : function(remainVisible){
31938 var v = this.getValue();
31939 if(this.revertInvalid !== false && !this.field.isValid()){
31940 v = this.startValue;
31941 this.cancelEdit(true);
31943 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31944 this.editing = false;
31948 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31949 this.editing = false;
31950 if(this.updateEl && this.boundEl){
31951 this.boundEl.update(v);
31953 if(remainVisible !== true){
31956 this.fireEvent("complete", this, v, this.startValue);
31961 onShow : function(){
31963 if(this.hideEl !== false){
31964 this.boundEl.hide();
31967 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31968 this.fixIEFocus = true;
31969 this.deferredFocus.defer(50, this);
31971 this.field.focus();
31973 this.fireEvent("startedit", this.boundEl, this.startValue);
31976 deferredFocus : function(){
31978 this.field.focus();
31983 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31984 * reverted to the original starting value.
31985 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31986 * cancel (defaults to false)
31988 cancelEdit : function(remainVisible){
31990 this.setValue(this.startValue);
31991 if(remainVisible !== true){
31998 onBlur : function(){
31999 if(this.allowBlur !== true && this.editing){
32000 this.completeEdit();
32005 onHide : function(){
32007 this.completeEdit();
32011 if(this.field.collapse){
32012 this.field.collapse();
32015 if(this.hideEl !== false){
32016 this.boundEl.show();
32019 Roo.QuickTips.enable();
32024 * Sets the data value of the editor
32025 * @param {Mixed} value Any valid value supported by the underlying field
32027 setValue : function(v){
32028 this.field.setValue(v);
32032 * Gets the data value of the editor
32033 * @return {Mixed} The data value
32035 getValue : function(){
32036 return this.field.getValue();
32040 * Ext JS Library 1.1.1
32041 * Copyright(c) 2006-2007, Ext JS, LLC.
32043 * Originally Released Under LGPL - original licence link has changed is not relivant.
32046 * <script type="text/javascript">
32050 * @class Roo.BasicDialog
32051 * @extends Roo.util.Observable
32052 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32054 var dlg = new Roo.BasicDialog("my-dlg", {
32063 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32064 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32065 dlg.addButton('Cancel', dlg.hide, dlg);
32068 <b>A Dialog should always be a direct child of the body element.</b>
32069 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32070 * @cfg {String} title Default text to display in the title bar (defaults to null)
32071 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32072 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32073 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32074 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32075 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32076 * (defaults to null with no animation)
32077 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32078 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32079 * property for valid values (defaults to 'all')
32080 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32081 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32082 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32083 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32084 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32085 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32086 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32087 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32088 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32089 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32090 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32091 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32092 * draggable = true (defaults to false)
32093 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32094 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32095 * shadow (defaults to false)
32096 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32097 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32098 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32099 * @cfg {Array} buttons Array of buttons
32100 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32102 * Create a new BasicDialog.
32103 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32104 * @param {Object} config Configuration options
32106 Roo.BasicDialog = function(el, config){
32107 this.el = Roo.get(el);
32108 var dh = Roo.DomHelper;
32109 if(!this.el && config && config.autoCreate){
32110 if(typeof config.autoCreate == "object"){
32111 if(!config.autoCreate.id){
32112 config.autoCreate.id = el;
32114 this.el = dh.append(document.body,
32115 config.autoCreate, true);
32117 this.el = dh.append(document.body,
32118 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32122 el.setDisplayed(true);
32123 el.hide = this.hideAction;
32125 el.addClass("x-dlg");
32127 Roo.apply(this, config);
32129 this.proxy = el.createProxy("x-dlg-proxy");
32130 this.proxy.hide = this.hideAction;
32131 this.proxy.setOpacity(.5);
32135 el.setWidth(config.width);
32138 el.setHeight(config.height);
32140 this.size = el.getSize();
32141 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32142 this.xy = [config.x,config.y];
32144 this.xy = el.getCenterXY(true);
32146 /** The header element @type Roo.Element */
32147 this.header = el.child("> .x-dlg-hd");
32148 /** The body element @type Roo.Element */
32149 this.body = el.child("> .x-dlg-bd");
32150 /** The footer element @type Roo.Element */
32151 this.footer = el.child("> .x-dlg-ft");
32154 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32157 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32160 this.header.unselectable();
32162 this.header.update(this.title);
32164 // this element allows the dialog to be focused for keyboard event
32165 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32166 this.focusEl.swallowEvent("click", true);
32168 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32170 // wrap the body and footer for special rendering
32171 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32173 this.bwrap.dom.appendChild(this.footer.dom);
32176 this.bg = this.el.createChild({
32177 tag: "div", cls:"x-dlg-bg",
32178 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32180 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32183 if(this.autoScroll !== false && !this.autoTabs){
32184 this.body.setStyle("overflow", "auto");
32187 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32189 if(this.closable !== false){
32190 this.el.addClass("x-dlg-closable");
32191 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32192 this.close.on("click", this.closeClick, this);
32193 this.close.addClassOnOver("x-dlg-close-over");
32195 if(this.collapsible !== false){
32196 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32197 this.collapseBtn.on("click", this.collapseClick, this);
32198 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32199 this.header.on("dblclick", this.collapseClick, this);
32201 if(this.resizable !== false){
32202 this.el.addClass("x-dlg-resizable");
32203 this.resizer = new Roo.Resizable(el, {
32204 minWidth: this.minWidth || 80,
32205 minHeight:this.minHeight || 80,
32206 handles: this.resizeHandles || "all",
32209 this.resizer.on("beforeresize", this.beforeResize, this);
32210 this.resizer.on("resize", this.onResize, this);
32212 if(this.draggable !== false){
32213 el.addClass("x-dlg-draggable");
32214 if (!this.proxyDrag) {
32215 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32218 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32220 dd.setHandleElId(this.header.id);
32221 dd.endDrag = this.endMove.createDelegate(this);
32222 dd.startDrag = this.startMove.createDelegate(this);
32223 dd.onDrag = this.onDrag.createDelegate(this);
32228 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32229 this.mask.enableDisplayMode("block");
32231 this.el.addClass("x-dlg-modal");
32234 this.shadow = new Roo.Shadow({
32235 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32236 offset : this.shadowOffset
32239 this.shadowOffset = 0;
32241 if(Roo.useShims && this.shim !== false){
32242 this.shim = this.el.createShim();
32243 this.shim.hide = this.hideAction;
32251 if (this.buttons) {
32252 var bts= this.buttons;
32254 Roo.each(bts, function(b) {
32263 * Fires when a key is pressed
32264 * @param {Roo.BasicDialog} this
32265 * @param {Roo.EventObject} e
32270 * Fires when this dialog is moved by the user.
32271 * @param {Roo.BasicDialog} this
32272 * @param {Number} x The new page X
32273 * @param {Number} y The new page Y
32278 * Fires when this dialog is resized by the user.
32279 * @param {Roo.BasicDialog} this
32280 * @param {Number} width The new width
32281 * @param {Number} height The new height
32285 * @event beforehide
32286 * Fires before this dialog is hidden.
32287 * @param {Roo.BasicDialog} this
32289 "beforehide" : true,
32292 * Fires when this dialog is hidden.
32293 * @param {Roo.BasicDialog} this
32297 * @event beforeshow
32298 * Fires before this dialog is shown.
32299 * @param {Roo.BasicDialog} this
32301 "beforeshow" : true,
32304 * Fires when this dialog is shown.
32305 * @param {Roo.BasicDialog} this
32309 el.on("keydown", this.onKeyDown, this);
32310 el.on("mousedown", this.toFront, this);
32311 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32313 Roo.DialogManager.register(this);
32314 Roo.BasicDialog.superclass.constructor.call(this);
32317 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32318 shadowOffset: Roo.isIE ? 6 : 5,
32321 minButtonWidth: 75,
32322 defaultButton: null,
32323 buttonAlign: "right",
32328 * Sets the dialog title text
32329 * @param {String} text The title text to display
32330 * @return {Roo.BasicDialog} this
32332 setTitle : function(text){
32333 this.header.update(text);
32338 closeClick : function(){
32343 collapseClick : function(){
32344 this[this.collapsed ? "expand" : "collapse"]();
32348 * Collapses the dialog to its minimized state (only the title bar is visible).
32349 * Equivalent to the user clicking the collapse dialog button.
32351 collapse : function(){
32352 if(!this.collapsed){
32353 this.collapsed = true;
32354 this.el.addClass("x-dlg-collapsed");
32355 this.restoreHeight = this.el.getHeight();
32356 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32361 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32362 * clicking the expand dialog button.
32364 expand : function(){
32365 if(this.collapsed){
32366 this.collapsed = false;
32367 this.el.removeClass("x-dlg-collapsed");
32368 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32373 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32374 * @return {Roo.TabPanel} The tabs component
32376 initTabs : function(){
32377 var tabs = this.getTabs();
32378 while(tabs.getTab(0)){
32381 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32383 tabs.addTab(Roo.id(dom), dom.title);
32391 beforeResize : function(){
32392 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32396 onResize : function(){
32397 this.refreshSize();
32398 this.syncBodyHeight();
32399 this.adjustAssets();
32401 this.fireEvent("resize", this, this.size.width, this.size.height);
32405 onKeyDown : function(e){
32406 if(this.isVisible()){
32407 this.fireEvent("keydown", this, e);
32412 * Resizes the dialog.
32413 * @param {Number} width
32414 * @param {Number} height
32415 * @return {Roo.BasicDialog} this
32417 resizeTo : function(width, height){
32418 this.el.setSize(width, height);
32419 this.size = {width: width, height: height};
32420 this.syncBodyHeight();
32421 if(this.fixedcenter){
32424 if(this.isVisible()){
32425 this.constrainXY();
32426 this.adjustAssets();
32428 this.fireEvent("resize", this, width, height);
32434 * Resizes the dialog to fit the specified content size.
32435 * @param {Number} width
32436 * @param {Number} height
32437 * @return {Roo.BasicDialog} this
32439 setContentSize : function(w, h){
32440 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32441 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32442 //if(!this.el.isBorderBox()){
32443 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32444 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32447 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32448 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32450 this.resizeTo(w, h);
32455 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32456 * executed in response to a particular key being pressed while the dialog is active.
32457 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32458 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32459 * @param {Function} fn The function to call
32460 * @param {Object} scope (optional) The scope of the function
32461 * @return {Roo.BasicDialog} this
32463 addKeyListener : function(key, fn, scope){
32464 var keyCode, shift, ctrl, alt;
32465 if(typeof key == "object" && !(key instanceof Array)){
32466 keyCode = key["key"];
32467 shift = key["shift"];
32468 ctrl = key["ctrl"];
32473 var handler = function(dlg, e){
32474 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32475 var k = e.getKey();
32476 if(keyCode instanceof Array){
32477 for(var i = 0, len = keyCode.length; i < len; i++){
32478 if(keyCode[i] == k){
32479 fn.call(scope || window, dlg, k, e);
32485 fn.call(scope || window, dlg, k, e);
32490 this.on("keydown", handler);
32495 * Returns the TabPanel component (creates it if it doesn't exist).
32496 * Note: If you wish to simply check for the existence of tabs without creating them,
32497 * check for a null 'tabs' property.
32498 * @return {Roo.TabPanel} The tabs component
32500 getTabs : function(){
32502 this.el.addClass("x-dlg-auto-tabs");
32503 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32504 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32510 * Adds a button to the footer section of the dialog.
32511 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32512 * object or a valid Roo.DomHelper element config
32513 * @param {Function} handler The function called when the button is clicked
32514 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32515 * @return {Roo.Button} The new button
32517 addButton : function(config, handler, scope){
32518 var dh = Roo.DomHelper;
32520 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32522 if(!this.btnContainer){
32523 var tb = this.footer.createChild({
32525 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32526 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32528 this.btnContainer = tb.firstChild.firstChild.firstChild;
32533 minWidth: this.minButtonWidth,
32536 if(typeof config == "string"){
32537 bconfig.text = config;
32540 bconfig.dhconfig = config;
32542 Roo.apply(bconfig, config);
32546 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32547 bconfig.position = Math.max(0, bconfig.position);
32548 fc = this.btnContainer.childNodes[bconfig.position];
32551 var btn = new Roo.Button(
32553 this.btnContainer.insertBefore(document.createElement("td"),fc)
32554 : this.btnContainer.appendChild(document.createElement("td")),
32555 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32558 this.syncBodyHeight();
32561 * Array of all the buttons that have been added to this dialog via addButton
32566 this.buttons.push(btn);
32571 * Sets the default button to be focused when the dialog is displayed.
32572 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32573 * @return {Roo.BasicDialog} this
32575 setDefaultButton : function(btn){
32576 this.defaultButton = btn;
32581 getHeaderFooterHeight : function(safe){
32584 height += this.header.getHeight();
32587 var fm = this.footer.getMargins();
32588 height += (this.footer.getHeight()+fm.top+fm.bottom);
32590 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32591 height += this.centerBg.getPadding("tb");
32596 syncBodyHeight : function()
32598 var bd = this.body, // the text
32599 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32601 var height = this.size.height - this.getHeaderFooterHeight(false);
32602 bd.setHeight(height-bd.getMargins("tb"));
32603 var hh = this.header.getHeight();
32604 var h = this.size.height-hh;
32607 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32608 bw.setHeight(h-cb.getPadding("tb"));
32610 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32611 bd.setWidth(bw.getWidth(true));
32613 this.tabs.syncHeight();
32615 this.tabs.el.repaint();
32621 * Restores the previous state of the dialog if Roo.state is configured.
32622 * @return {Roo.BasicDialog} this
32624 restoreState : function(){
32625 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32626 if(box && box.width){
32627 this.xy = [box.x, box.y];
32628 this.resizeTo(box.width, box.height);
32634 beforeShow : function(){
32636 if(this.fixedcenter){
32637 this.xy = this.el.getCenterXY(true);
32640 Roo.get(document.body).addClass("x-body-masked");
32641 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32644 this.constrainXY();
32648 animShow : function(){
32649 var b = Roo.get(this.animateTarget).getBox();
32650 this.proxy.setSize(b.width, b.height);
32651 this.proxy.setLocation(b.x, b.y);
32653 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32654 true, .35, this.showEl.createDelegate(this));
32658 * Shows the dialog.
32659 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32660 * @return {Roo.BasicDialog} this
32662 show : function(animateTarget){
32663 if (this.fireEvent("beforeshow", this) === false){
32666 if(this.syncHeightBeforeShow){
32667 this.syncBodyHeight();
32668 }else if(this.firstShow){
32669 this.firstShow = false;
32670 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32672 this.animateTarget = animateTarget || this.animateTarget;
32673 if(!this.el.isVisible()){
32675 if(this.animateTarget && Roo.get(this.animateTarget)){
32685 showEl : function(){
32687 this.el.setXY(this.xy);
32689 this.adjustAssets(true);
32692 // IE peekaboo bug - fix found by Dave Fenwick
32696 this.fireEvent("show", this);
32700 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32701 * dialog itself will receive focus.
32703 focus : function(){
32704 if(this.defaultButton){
32705 this.defaultButton.focus();
32707 this.focusEl.focus();
32712 constrainXY : function(){
32713 if(this.constraintoviewport !== false){
32714 if(!this.viewSize){
32715 if(this.container){
32716 var s = this.container.getSize();
32717 this.viewSize = [s.width, s.height];
32719 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32722 var s = Roo.get(this.container||document).getScroll();
32724 var x = this.xy[0], y = this.xy[1];
32725 var w = this.size.width, h = this.size.height;
32726 var vw = this.viewSize[0], vh = this.viewSize[1];
32727 // only move it if it needs it
32729 // first validate right/bottom
32730 if(x + w > vw+s.left){
32734 if(y + h > vh+s.top){
32738 // then make sure top/left isn't negative
32750 if(this.isVisible()){
32751 this.el.setLocation(x, y);
32752 this.adjustAssets();
32759 onDrag : function(){
32760 if(!this.proxyDrag){
32761 this.xy = this.el.getXY();
32762 this.adjustAssets();
32767 adjustAssets : function(doShow){
32768 var x = this.xy[0], y = this.xy[1];
32769 var w = this.size.width, h = this.size.height;
32770 if(doShow === true){
32772 this.shadow.show(this.el);
32778 if(this.shadow && this.shadow.isVisible()){
32779 this.shadow.show(this.el);
32781 if(this.shim && this.shim.isVisible()){
32782 this.shim.setBounds(x, y, w, h);
32787 adjustViewport : function(w, h){
32789 w = Roo.lib.Dom.getViewWidth();
32790 h = Roo.lib.Dom.getViewHeight();
32793 this.viewSize = [w, h];
32794 if(this.modal && this.mask.isVisible()){
32795 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32796 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32798 if(this.isVisible()){
32799 this.constrainXY();
32804 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32805 * shadow, proxy, mask, etc.) Also removes all event listeners.
32806 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32808 destroy : function(removeEl){
32809 if(this.isVisible()){
32810 this.animateTarget = null;
32813 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32815 this.tabs.destroy(removeEl);
32828 for(var i = 0, len = this.buttons.length; i < len; i++){
32829 this.buttons[i].destroy();
32832 this.el.removeAllListeners();
32833 if(removeEl === true){
32834 this.el.update("");
32837 Roo.DialogManager.unregister(this);
32841 startMove : function(){
32842 if(this.proxyDrag){
32845 if(this.constraintoviewport !== false){
32846 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32851 endMove : function(){
32852 if(!this.proxyDrag){
32853 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32855 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32858 this.refreshSize();
32859 this.adjustAssets();
32861 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32865 * Brings this dialog to the front of any other visible dialogs
32866 * @return {Roo.BasicDialog} this
32868 toFront : function(){
32869 Roo.DialogManager.bringToFront(this);
32874 * Sends this dialog to the back (under) of any other visible dialogs
32875 * @return {Roo.BasicDialog} this
32877 toBack : function(){
32878 Roo.DialogManager.sendToBack(this);
32883 * Centers this dialog in the viewport
32884 * @return {Roo.BasicDialog} this
32886 center : function(){
32887 var xy = this.el.getCenterXY(true);
32888 this.moveTo(xy[0], xy[1]);
32893 * Moves the dialog's top-left corner to the specified point
32894 * @param {Number} x
32895 * @param {Number} y
32896 * @return {Roo.BasicDialog} this
32898 moveTo : function(x, y){
32900 if(this.isVisible()){
32901 this.el.setXY(this.xy);
32902 this.adjustAssets();
32908 * Aligns the dialog to the specified element
32909 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32910 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32911 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32912 * @return {Roo.BasicDialog} this
32914 alignTo : function(element, position, offsets){
32915 this.xy = this.el.getAlignToXY(element, position, offsets);
32916 if(this.isVisible()){
32917 this.el.setXY(this.xy);
32918 this.adjustAssets();
32924 * Anchors an element to another element and realigns it when the window is resized.
32925 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32926 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32927 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32928 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32929 * is a number, it is used as the buffer delay (defaults to 50ms).
32930 * @return {Roo.BasicDialog} this
32932 anchorTo : function(el, alignment, offsets, monitorScroll){
32933 var action = function(){
32934 this.alignTo(el, alignment, offsets);
32936 Roo.EventManager.onWindowResize(action, this);
32937 var tm = typeof monitorScroll;
32938 if(tm != 'undefined'){
32939 Roo.EventManager.on(window, 'scroll', action, this,
32940 {buffer: tm == 'number' ? monitorScroll : 50});
32947 * Returns true if the dialog is visible
32948 * @return {Boolean}
32950 isVisible : function(){
32951 return this.el.isVisible();
32955 animHide : function(callback){
32956 var b = Roo.get(this.animateTarget).getBox();
32958 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32960 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32961 this.hideEl.createDelegate(this, [callback]));
32965 * Hides the dialog.
32966 * @param {Function} callback (optional) Function to call when the dialog is hidden
32967 * @return {Roo.BasicDialog} this
32969 hide : function(callback){
32970 if (this.fireEvent("beforehide", this) === false){
32974 this.shadow.hide();
32979 // sometimes animateTarget seems to get set.. causing problems...
32980 // this just double checks..
32981 if(this.animateTarget && Roo.get(this.animateTarget)) {
32982 this.animHide(callback);
32985 this.hideEl(callback);
32991 hideEl : function(callback){
32995 Roo.get(document.body).removeClass("x-body-masked");
32997 this.fireEvent("hide", this);
32998 if(typeof callback == "function"){
33004 hideAction : function(){
33005 this.setLeft("-10000px");
33006 this.setTop("-10000px");
33007 this.setStyle("visibility", "hidden");
33011 refreshSize : function(){
33012 this.size = this.el.getSize();
33013 this.xy = this.el.getXY();
33014 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
33018 // z-index is managed by the DialogManager and may be overwritten at any time
33019 setZIndex : function(index){
33021 this.mask.setStyle("z-index", index);
33024 this.shim.setStyle("z-index", ++index);
33027 this.shadow.setZIndex(++index);
33029 this.el.setStyle("z-index", ++index);
33031 this.proxy.setStyle("z-index", ++index);
33034 this.resizer.proxy.setStyle("z-index", ++index);
33037 this.lastZIndex = index;
33041 * Returns the element for this dialog
33042 * @return {Roo.Element} The underlying dialog Element
33044 getEl : function(){
33050 * @class Roo.DialogManager
33051 * Provides global access to BasicDialogs that have been created and
33052 * support for z-indexing (layering) multiple open dialogs.
33054 Roo.DialogManager = function(){
33056 var accessList = [];
33060 var sortDialogs = function(d1, d2){
33061 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33065 var orderDialogs = function(){
33066 accessList.sort(sortDialogs);
33067 var seed = Roo.DialogManager.zseed;
33068 for(var i = 0, len = accessList.length; i < len; i++){
33069 var dlg = accessList[i];
33071 dlg.setZIndex(seed + (i*10));
33078 * The starting z-index for BasicDialogs (defaults to 9000)
33079 * @type Number The z-index value
33084 register : function(dlg){
33085 list[dlg.id] = dlg;
33086 accessList.push(dlg);
33090 unregister : function(dlg){
33091 delete list[dlg.id];
33094 if(!accessList.indexOf){
33095 for( i = 0, len = accessList.length; i < len; i++){
33096 if(accessList[i] == dlg){
33097 accessList.splice(i, 1);
33102 i = accessList.indexOf(dlg);
33104 accessList.splice(i, 1);
33110 * Gets a registered dialog by id
33111 * @param {String/Object} id The id of the dialog or a dialog
33112 * @return {Roo.BasicDialog} this
33114 get : function(id){
33115 return typeof id == "object" ? id : list[id];
33119 * Brings the specified dialog to the front
33120 * @param {String/Object} dlg The id of the dialog or a dialog
33121 * @return {Roo.BasicDialog} this
33123 bringToFront : function(dlg){
33124 dlg = this.get(dlg);
33127 dlg._lastAccess = new Date().getTime();
33134 * Sends the specified dialog to the back
33135 * @param {String/Object} dlg The id of the dialog or a dialog
33136 * @return {Roo.BasicDialog} this
33138 sendToBack : function(dlg){
33139 dlg = this.get(dlg);
33140 dlg._lastAccess = -(new Date().getTime());
33146 * Hides all dialogs
33148 hideAll : function(){
33149 for(var id in list){
33150 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33159 * @class Roo.LayoutDialog
33160 * @extends Roo.BasicDialog
33161 * Dialog which provides adjustments for working with a layout in a Dialog.
33162 * Add your necessary layout config options to the dialog's config.<br>
33163 * Example usage (including a nested layout):
33166 dialog = new Roo.LayoutDialog("download-dlg", {
33175 // layout config merges with the dialog config
33177 tabPosition: "top",
33178 alwaysShowTabs: true
33181 dialog.addKeyListener(27, dialog.hide, dialog);
33182 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33183 dialog.addButton("Build It!", this.getDownload, this);
33185 // we can even add nested layouts
33186 var innerLayout = new Roo.BorderLayout("dl-inner", {
33196 innerLayout.beginUpdate();
33197 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33198 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33199 innerLayout.endUpdate(true);
33201 var layout = dialog.getLayout();
33202 layout.beginUpdate();
33203 layout.add("center", new Roo.ContentPanel("standard-panel",
33204 {title: "Download the Source", fitToFrame:true}));
33205 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33206 {title: "Build your own roo.js"}));
33207 layout.getRegion("center").showPanel(sp);
33208 layout.endUpdate();
33212 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33213 * @param {Object} config configuration options
33215 Roo.LayoutDialog = function(el, cfg){
33218 if (typeof(cfg) == 'undefined') {
33219 config = Roo.apply({}, el);
33220 // not sure why we use documentElement here.. - it should always be body.
33221 // IE7 borks horribly if we use documentElement.
33222 // webkit also does not like documentElement - it creates a body element...
33223 el = Roo.get( document.body || document.documentElement ).createChild();
33224 //config.autoCreate = true;
33228 config.autoTabs = false;
33229 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33230 this.body.setStyle({overflow:"hidden", position:"relative"});
33231 this.layout = new Roo.BorderLayout(this.body.dom, config);
33232 this.layout.monitorWindowResize = false;
33233 this.el.addClass("x-dlg-auto-layout");
33234 // fix case when center region overwrites center function
33235 this.center = Roo.BasicDialog.prototype.center;
33236 this.on("show", this.layout.layout, this.layout, true);
33237 if (config.items) {
33238 var xitems = config.items;
33239 delete config.items;
33240 Roo.each(xitems, this.addxtype, this);
33245 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33247 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33250 endUpdate : function(){
33251 this.layout.endUpdate();
33255 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33258 beginUpdate : function(){
33259 this.layout.beginUpdate();
33263 * Get the BorderLayout for this dialog
33264 * @return {Roo.BorderLayout}
33266 getLayout : function(){
33267 return this.layout;
33270 showEl : function(){
33271 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33273 this.layout.layout();
33278 // Use the syncHeightBeforeShow config option to control this automatically
33279 syncBodyHeight : function(){
33280 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33281 if(this.layout){this.layout.layout();}
33285 * Add an xtype element (actually adds to the layout.)
33286 * @return {Object} xdata xtype object data.
33289 addxtype : function(c) {
33290 return this.layout.addxtype(c);
33294 * Ext JS Library 1.1.1
33295 * Copyright(c) 2006-2007, Ext JS, LLC.
33297 * Originally Released Under LGPL - original licence link has changed is not relivant.
33300 * <script type="text/javascript">
33304 * @class Roo.MessageBox
33305 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33309 Roo.Msg.alert('Status', 'Changes saved successfully.');
33311 // Prompt for user data:
33312 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33314 // process text value...
33318 // Show a dialog using config options:
33320 title:'Save Changes?',
33321 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33322 buttons: Roo.Msg.YESNOCANCEL,
33329 Roo.MessageBox = function(){
33330 var dlg, opt, mask, waitTimer;
33331 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33332 var buttons, activeTextEl, bwidth;
33335 var handleButton = function(button){
33337 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33341 var handleHide = function(){
33342 if(opt && opt.cls){
33343 dlg.el.removeClass(opt.cls);
33346 Roo.TaskMgr.stop(waitTimer);
33352 var updateButtons = function(b){
33355 buttons["ok"].hide();
33356 buttons["cancel"].hide();
33357 buttons["yes"].hide();
33358 buttons["no"].hide();
33359 dlg.footer.dom.style.display = 'none';
33362 dlg.footer.dom.style.display = '';
33363 for(var k in buttons){
33364 if(typeof buttons[k] != "function"){
33367 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33368 width += buttons[k].el.getWidth()+15;
33378 var handleEsc = function(d, k, e){
33379 if(opt && opt.closable !== false){
33389 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33390 * @return {Roo.BasicDialog} The BasicDialog element
33392 getDialog : function(){
33394 dlg = new Roo.BasicDialog("x-msg-box", {
33399 constraintoviewport:false,
33401 collapsible : false,
33404 width:400, height:100,
33405 buttonAlign:"center",
33406 closeClick : function(){
33407 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33408 handleButton("no");
33410 handleButton("cancel");
33414 dlg.on("hide", handleHide);
33416 dlg.addKeyListener(27, handleEsc);
33418 var bt = this.buttonText;
33419 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33420 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33421 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33422 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33423 bodyEl = dlg.body.createChild({
33425 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>'
33427 msgEl = bodyEl.dom.firstChild;
33428 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33429 textboxEl.enableDisplayMode();
33430 textboxEl.addKeyListener([10,13], function(){
33431 if(dlg.isVisible() && opt && opt.buttons){
33432 if(opt.buttons.ok){
33433 handleButton("ok");
33434 }else if(opt.buttons.yes){
33435 handleButton("yes");
33439 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33440 textareaEl.enableDisplayMode();
33441 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33442 progressEl.enableDisplayMode();
33443 var pf = progressEl.dom.firstChild;
33445 pp = Roo.get(pf.firstChild);
33446 pp.setHeight(pf.offsetHeight);
33454 * Updates the message box body text
33455 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33456 * the XHTML-compliant non-breaking space character '&#160;')
33457 * @return {Roo.MessageBox} This message box
33459 updateText : function(text){
33460 if(!dlg.isVisible() && !opt.width){
33461 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33463 msgEl.innerHTML = text || ' ';
33465 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33466 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33468 Math.min(opt.width || cw , this.maxWidth),
33469 Math.max(opt.minWidth || this.minWidth, bwidth)
33472 activeTextEl.setWidth(w);
33474 if(dlg.isVisible()){
33475 dlg.fixedcenter = false;
33477 // to big, make it scroll. = But as usual stupid IE does not support
33480 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33481 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33482 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33484 bodyEl.dom.style.height = '';
33485 bodyEl.dom.style.overflowY = '';
33488 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33490 bodyEl.dom.style.overflowX = '';
33493 dlg.setContentSize(w, bodyEl.getHeight());
33494 if(dlg.isVisible()){
33495 dlg.fixedcenter = true;
33501 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33502 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33503 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33504 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33505 * @return {Roo.MessageBox} This message box
33507 updateProgress : function(value, text){
33509 this.updateText(text);
33511 if (pp) { // weird bug on my firefox - for some reason this is not defined
33512 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33518 * Returns true if the message box is currently displayed
33519 * @return {Boolean} True if the message box is visible, else false
33521 isVisible : function(){
33522 return dlg && dlg.isVisible();
33526 * Hides the message box if it is displayed
33529 if(this.isVisible()){
33535 * Displays a new message box, or reinitializes an existing message box, based on the config options
33536 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33537 * The following config object properties are supported:
33539 Property Type Description
33540 ---------- --------------- ------------------------------------------------------------------------------------
33541 animEl String/Element An id or Element from which the message box should animate as it opens and
33542 closes (defaults to undefined)
33543 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33544 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33545 closable Boolean False to hide the top-right close button (defaults to true). Note that
33546 progress and wait dialogs will ignore this property and always hide the
33547 close button as they can only be closed programmatically.
33548 cls String A custom CSS class to apply to the message box element
33549 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33550 displayed (defaults to 75)
33551 fn Function A callback function to execute after closing the dialog. The arguments to the
33552 function will be btn (the name of the button that was clicked, if applicable,
33553 e.g. "ok"), and text (the value of the active text field, if applicable).
33554 Progress and wait dialogs will ignore this option since they do not respond to
33555 user actions and can only be closed programmatically, so any required function
33556 should be called by the same code after it closes the dialog.
33557 icon String A CSS class that provides a background image to be used as an icon for
33558 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33559 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33560 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33561 modal Boolean False to allow user interaction with the page while the message box is
33562 displayed (defaults to true)
33563 msg String A string that will replace the existing message box body text (defaults
33564 to the XHTML-compliant non-breaking space character ' ')
33565 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33566 progress Boolean True to display a progress bar (defaults to false)
33567 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33568 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33569 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33570 title String The title text
33571 value String The string value to set into the active textbox element if displayed
33572 wait Boolean True to display a progress bar (defaults to false)
33573 width Number The width of the dialog in pixels
33580 msg: 'Please enter your address:',
33582 buttons: Roo.MessageBox.OKCANCEL,
33585 animEl: 'addAddressBtn'
33588 * @param {Object} config Configuration options
33589 * @return {Roo.MessageBox} This message box
33591 show : function(options)
33594 // this causes nightmares if you show one dialog after another
33595 // especially on callbacks..
33597 if(this.isVisible()){
33600 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33601 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33602 Roo.log("New Dialog Message:" + options.msg )
33603 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33604 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33607 var d = this.getDialog();
33609 d.setTitle(opt.title || " ");
33610 d.close.setDisplayed(opt.closable !== false);
33611 activeTextEl = textboxEl;
33612 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33617 textareaEl.setHeight(typeof opt.multiline == "number" ?
33618 opt.multiline : this.defaultTextHeight);
33619 activeTextEl = textareaEl;
33628 progressEl.setDisplayed(opt.progress === true);
33629 this.updateProgress(0);
33630 activeTextEl.dom.value = opt.value || "";
33632 dlg.setDefaultButton(activeTextEl);
33634 var bs = opt.buttons;
33637 db = buttons["ok"];
33638 }else if(bs && bs.yes){
33639 db = buttons["yes"];
33641 dlg.setDefaultButton(db);
33643 bwidth = updateButtons(opt.buttons);
33644 this.updateText(opt.msg);
33646 d.el.addClass(opt.cls);
33648 d.proxyDrag = opt.proxyDrag === true;
33649 d.modal = opt.modal !== false;
33650 d.mask = opt.modal !== false ? mask : false;
33651 if(!d.isVisible()){
33652 // force it to the end of the z-index stack so it gets a cursor in FF
33653 document.body.appendChild(dlg.el.dom);
33654 d.animateTarget = null;
33655 d.show(options.animEl);
33661 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33662 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33663 * and closing the message box when the process is complete.
33664 * @param {String} title The title bar text
33665 * @param {String} msg The message box body text
33666 * @return {Roo.MessageBox} This message box
33668 progress : function(title, msg){
33675 minWidth: this.minProgressWidth,
33682 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33683 * If a callback function is passed it will be called after the user clicks the button, and the
33684 * id of the button that was clicked will be passed as the only parameter to the callback
33685 * (could also be the top-right close button).
33686 * @param {String} title The title bar text
33687 * @param {String} msg The message box body text
33688 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33689 * @param {Object} scope (optional) The scope of the callback function
33690 * @return {Roo.MessageBox} This message box
33692 alert : function(title, msg, fn, scope){
33705 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33706 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33707 * You are responsible for closing the message box when the process is complete.
33708 * @param {String} msg The message box body text
33709 * @param {String} title (optional) The title bar text
33710 * @return {Roo.MessageBox} This message box
33712 wait : function(msg, title){
33723 waitTimer = Roo.TaskMgr.start({
33725 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33733 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33734 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33735 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33736 * @param {String} title The title bar text
33737 * @param {String} msg The message box body text
33738 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33739 * @param {Object} scope (optional) The scope of the callback function
33740 * @return {Roo.MessageBox} This message box
33742 confirm : function(title, msg, fn, scope){
33746 buttons: this.YESNO,
33755 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33756 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33757 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33758 * (could also be the top-right close button) and the text that was entered will be passed as the two
33759 * parameters to the callback.
33760 * @param {String} title The title bar text
33761 * @param {String} msg The message box body text
33762 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33763 * @param {Object} scope (optional) The scope of the callback function
33764 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33765 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33766 * @return {Roo.MessageBox} This message box
33768 prompt : function(title, msg, fn, scope, multiline){
33772 buttons: this.OKCANCEL,
33777 multiline: multiline,
33784 * Button config that displays a single OK button
33789 * Button config that displays Yes and No buttons
33792 YESNO : {yes:true, no:true},
33794 * Button config that displays OK and Cancel buttons
33797 OKCANCEL : {ok:true, cancel:true},
33799 * Button config that displays Yes, No and Cancel buttons
33802 YESNOCANCEL : {yes:true, no:true, cancel:true},
33805 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33808 defaultTextHeight : 75,
33810 * The maximum width in pixels of the message box (defaults to 600)
33815 * The minimum width in pixels of the message box (defaults to 100)
33820 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33821 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33824 minProgressWidth : 250,
33826 * An object containing the default button text strings that can be overriden for localized language support.
33827 * Supported properties are: ok, cancel, yes and no.
33828 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33841 * Shorthand for {@link Roo.MessageBox}
33843 Roo.Msg = Roo.MessageBox;/*
33845 * Ext JS Library 1.1.1
33846 * Copyright(c) 2006-2007, Ext JS, LLC.
33848 * Originally Released Under LGPL - original licence link has changed is not relivant.
33851 * <script type="text/javascript">
33854 * @class Roo.QuickTips
33855 * Provides attractive and customizable tooltips for any element.
33858 Roo.QuickTips = function(){
33859 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33860 var ce, bd, xy, dd;
33861 var visible = false, disabled = true, inited = false;
33862 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33864 var onOver = function(e){
33868 var t = e.getTarget();
33869 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33872 if(ce && t == ce.el){
33873 clearTimeout(hideProc);
33876 if(t && tagEls[t.id]){
33877 tagEls[t.id].el = t;
33878 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33881 var ttp, et = Roo.fly(t);
33882 var ns = cfg.namespace;
33883 if(tm.interceptTitles && t.title){
33886 t.removeAttribute("title");
33887 e.preventDefault();
33889 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33892 showProc = show.defer(tm.showDelay, tm, [{
33894 text: ttp.replace(/\\n/g,'<br/>'),
33895 width: et.getAttributeNS(ns, cfg.width),
33896 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33897 title: et.getAttributeNS(ns, cfg.title),
33898 cls: et.getAttributeNS(ns, cfg.cls)
33903 var onOut = function(e){
33904 clearTimeout(showProc);
33905 var t = e.getTarget();
33906 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33907 hideProc = setTimeout(hide, tm.hideDelay);
33911 var onMove = function(e){
33917 if(tm.trackMouse && ce){
33922 var onDown = function(e){
33923 clearTimeout(showProc);
33924 clearTimeout(hideProc);
33926 if(tm.hideOnClick){
33929 tm.enable.defer(100, tm);
33934 var getPad = function(){
33935 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33938 var show = function(o){
33942 clearTimeout(dismissProc);
33944 if(removeCls){ // in case manually hidden
33945 el.removeClass(removeCls);
33949 el.addClass(ce.cls);
33950 removeCls = ce.cls;
33953 tipTitle.update(ce.title);
33956 tipTitle.update('');
33959 el.dom.style.width = tm.maxWidth+'px';
33960 //tipBody.dom.style.width = '';
33961 tipBodyText.update(o.text);
33962 var p = getPad(), w = ce.width;
33964 var td = tipBodyText.dom;
33965 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33966 if(aw > tm.maxWidth){
33968 }else if(aw < tm.minWidth){
33974 //tipBody.setWidth(w);
33975 el.setWidth(parseInt(w, 10) + p);
33976 if(ce.autoHide === false){
33977 close.setDisplayed(true);
33982 close.setDisplayed(false);
33988 el.avoidY = xy[1]-18;
33993 el.setStyle("visibility", "visible");
33994 el.fadeIn({callback: afterShow});
34000 var afterShow = function(){
34004 if(tm.autoDismiss && ce.autoHide !== false){
34005 dismissProc = setTimeout(hide, tm.autoDismissDelay);
34010 var hide = function(noanim){
34011 clearTimeout(dismissProc);
34012 clearTimeout(hideProc);
34014 if(el.isVisible()){
34016 if(noanim !== true && tm.animate){
34017 el.fadeOut({callback: afterHide});
34024 var afterHide = function(){
34027 el.removeClass(removeCls);
34034 * @cfg {Number} minWidth
34035 * The minimum width of the quick tip (defaults to 40)
34039 * @cfg {Number} maxWidth
34040 * The maximum width of the quick tip (defaults to 300)
34044 * @cfg {Boolean} interceptTitles
34045 * True to automatically use the element's DOM title value if available (defaults to false)
34047 interceptTitles : false,
34049 * @cfg {Boolean} trackMouse
34050 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34052 trackMouse : false,
34054 * @cfg {Boolean} hideOnClick
34055 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34057 hideOnClick : true,
34059 * @cfg {Number} showDelay
34060 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
34064 * @cfg {Number} hideDelay
34065 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34069 * @cfg {Boolean} autoHide
34070 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34071 * Used in conjunction with hideDelay.
34076 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34077 * (defaults to true). Used in conjunction with autoDismissDelay.
34079 autoDismiss : true,
34082 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34084 autoDismissDelay : 5000,
34086 * @cfg {Boolean} animate
34087 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34092 * @cfg {String} title
34093 * Title text to display (defaults to ''). This can be any valid HTML markup.
34097 * @cfg {String} text
34098 * Body text to display (defaults to ''). This can be any valid HTML markup.
34102 * @cfg {String} cls
34103 * A CSS class to apply to the base quick tip element (defaults to '').
34107 * @cfg {Number} width
34108 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34109 * minWidth or maxWidth.
34114 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34115 * or display QuickTips in a page.
34118 tm = Roo.QuickTips;
34119 cfg = tm.tagConfig;
34121 if(!Roo.isReady){ // allow calling of init() before onReady
34122 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34125 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34126 el.fxDefaults = {stopFx: true};
34127 // maximum custom styling
34128 //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>');
34129 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>');
34130 tipTitle = el.child('h3');
34131 tipTitle.enableDisplayMode("block");
34132 tipBody = el.child('div.x-tip-bd');
34133 tipBodyText = el.child('div.x-tip-bd-inner');
34134 //bdLeft = el.child('div.x-tip-bd-left');
34135 //bdRight = el.child('div.x-tip-bd-right');
34136 close = el.child('div.x-tip-close');
34137 close.enableDisplayMode("block");
34138 close.on("click", hide);
34139 var d = Roo.get(document);
34140 d.on("mousedown", onDown);
34141 d.on("mouseover", onOver);
34142 d.on("mouseout", onOut);
34143 d.on("mousemove", onMove);
34144 esc = d.addKeyListener(27, hide);
34147 dd = el.initDD("default", null, {
34148 onDrag : function(){
34152 dd.setHandleElId(tipTitle.id);
34161 * Configures a new quick tip instance and assigns it to a target element. The following config options
34164 Property Type Description
34165 ---------- --------------------- ------------------------------------------------------------------------
34166 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34168 * @param {Object} config The config object
34170 register : function(config){
34171 var cs = config instanceof Array ? config : arguments;
34172 for(var i = 0, len = cs.length; i < len; i++) {
34174 var target = c.target;
34176 if(target instanceof Array){
34177 for(var j = 0, jlen = target.length; j < jlen; j++){
34178 tagEls[target[j]] = c;
34181 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34188 * Removes this quick tip from its element and destroys it.
34189 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34191 unregister : function(el){
34192 delete tagEls[Roo.id(el)];
34196 * Enable this quick tip.
34198 enable : function(){
34199 if(inited && disabled){
34201 if(locks.length < 1){
34208 * Disable this quick tip.
34210 disable : function(){
34212 clearTimeout(showProc);
34213 clearTimeout(hideProc);
34214 clearTimeout(dismissProc);
34222 * Returns true if the quick tip is enabled, else false.
34224 isEnabled : function(){
34230 namespace : "roo", // was ext?? this may break..
34231 alt_namespace : "ext",
34232 attribute : "qtip",
34242 // backwards compat
34243 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34245 * Ext JS Library 1.1.1
34246 * Copyright(c) 2006-2007, Ext JS, LLC.
34248 * Originally Released Under LGPL - original licence link has changed is not relivant.
34251 * <script type="text/javascript">
34256 * @class Roo.tree.TreePanel
34257 * @extends Roo.data.Tree
34259 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34260 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34261 * @cfg {Boolean} enableDD true to enable drag and drop
34262 * @cfg {Boolean} enableDrag true to enable just drag
34263 * @cfg {Boolean} enableDrop true to enable just drop
34264 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34265 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34266 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34267 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34268 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34269 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34270 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34271 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34272 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34273 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34274 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34275 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34276 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34277 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34278 * @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>
34279 * @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>
34282 * @param {String/HTMLElement/Element} el The container element
34283 * @param {Object} config
34285 Roo.tree.TreePanel = function(el, config){
34287 var loader = false;
34289 root = config.root;
34290 delete config.root;
34292 if (config.loader) {
34293 loader = config.loader;
34294 delete config.loader;
34297 Roo.apply(this, config);
34298 Roo.tree.TreePanel.superclass.constructor.call(this);
34299 this.el = Roo.get(el);
34300 this.el.addClass('x-tree');
34301 //console.log(root);
34303 this.setRootNode( Roo.factory(root, Roo.tree));
34306 this.loader = Roo.factory(loader, Roo.tree);
34309 * Read-only. The id of the container element becomes this TreePanel's id.
34311 this.id = this.el.id;
34314 * @event beforeload
34315 * Fires before a node is loaded, return false to cancel
34316 * @param {Node} node The node being loaded
34318 "beforeload" : true,
34321 * Fires when a node is loaded
34322 * @param {Node} node The node that was loaded
34326 * @event textchange
34327 * Fires when the text for a node is changed
34328 * @param {Node} node The node
34329 * @param {String} text The new text
34330 * @param {String} oldText The old text
34332 "textchange" : true,
34334 * @event beforeexpand
34335 * Fires before a node is expanded, return false to cancel.
34336 * @param {Node} node The node
34337 * @param {Boolean} deep
34338 * @param {Boolean} anim
34340 "beforeexpand" : true,
34342 * @event beforecollapse
34343 * Fires before a node is collapsed, return false to cancel.
34344 * @param {Node} node The node
34345 * @param {Boolean} deep
34346 * @param {Boolean} anim
34348 "beforecollapse" : true,
34351 * Fires when a node is expanded
34352 * @param {Node} node The node
34356 * @event disabledchange
34357 * Fires when the disabled status of a node changes
34358 * @param {Node} node The node
34359 * @param {Boolean} disabled
34361 "disabledchange" : true,
34364 * Fires when a node is collapsed
34365 * @param {Node} node The node
34369 * @event beforeclick
34370 * Fires before click processing on a node. Return false to cancel the default action.
34371 * @param {Node} node The node
34372 * @param {Roo.EventObject} e The event object
34374 "beforeclick":true,
34376 * @event checkchange
34377 * Fires when a node with a checkbox's checked property changes
34378 * @param {Node} this This node
34379 * @param {Boolean} checked
34381 "checkchange":true,
34384 * Fires when a node is clicked
34385 * @param {Node} node The node
34386 * @param {Roo.EventObject} e The event object
34391 * Fires when a node is double clicked
34392 * @param {Node} node The node
34393 * @param {Roo.EventObject} e The event object
34397 * @event contextmenu
34398 * Fires when a node is right clicked
34399 * @param {Node} node The node
34400 * @param {Roo.EventObject} e The event object
34402 "contextmenu":true,
34404 * @event beforechildrenrendered
34405 * Fires right before the child nodes for a node are rendered
34406 * @param {Node} node The node
34408 "beforechildrenrendered":true,
34411 * Fires when a node starts being dragged
34412 * @param {Roo.tree.TreePanel} this
34413 * @param {Roo.tree.TreeNode} node
34414 * @param {event} e The raw browser event
34416 "startdrag" : true,
34419 * Fires when a drag operation is complete
34420 * @param {Roo.tree.TreePanel} this
34421 * @param {Roo.tree.TreeNode} node
34422 * @param {event} e The raw browser event
34427 * Fires when a dragged node is dropped on a valid DD target
34428 * @param {Roo.tree.TreePanel} this
34429 * @param {Roo.tree.TreeNode} node
34430 * @param {DD} dd The dd it was dropped on
34431 * @param {event} e The raw browser event
34435 * @event beforenodedrop
34436 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34437 * passed to handlers has the following properties:<br />
34438 * <ul style="padding:5px;padding-left:16px;">
34439 * <li>tree - The TreePanel</li>
34440 * <li>target - The node being targeted for the drop</li>
34441 * <li>data - The drag data from the drag source</li>
34442 * <li>point - The point of the drop - append, above or below</li>
34443 * <li>source - The drag source</li>
34444 * <li>rawEvent - Raw mouse event</li>
34445 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34446 * to be inserted by setting them on this object.</li>
34447 * <li>cancel - Set this to true to cancel the drop.</li>
34449 * @param {Object} dropEvent
34451 "beforenodedrop" : true,
34454 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34455 * passed to handlers has the following properties:<br />
34456 * <ul style="padding:5px;padding-left:16px;">
34457 * <li>tree - The TreePanel</li>
34458 * <li>target - The node being targeted for the drop</li>
34459 * <li>data - The drag data from the drag source</li>
34460 * <li>point - The point of the drop - append, above or below</li>
34461 * <li>source - The drag source</li>
34462 * <li>rawEvent - Raw mouse event</li>
34463 * <li>dropNode - Dropped node(s).</li>
34465 * @param {Object} dropEvent
34469 * @event nodedragover
34470 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34471 * passed to handlers has the following properties:<br />
34472 * <ul style="padding:5px;padding-left:16px;">
34473 * <li>tree - The TreePanel</li>
34474 * <li>target - The node being targeted for the drop</li>
34475 * <li>data - The drag data from the drag source</li>
34476 * <li>point - The point of the drop - append, above or below</li>
34477 * <li>source - The drag source</li>
34478 * <li>rawEvent - Raw mouse event</li>
34479 * <li>dropNode - Drop node(s) provided by the source.</li>
34480 * <li>cancel - Set this to true to signal drop not allowed.</li>
34482 * @param {Object} dragOverEvent
34484 "nodedragover" : true,
34486 * @event appendnode
34487 * Fires when append node to the tree
34488 * @param {Roo.tree.TreePanel} this
34489 * @param {Roo.tree.TreeNode} node
34490 * @param {Number} index The index of the newly appended node
34492 "appendnode" : true
34495 if(this.singleExpand){
34496 this.on("beforeexpand", this.restrictExpand, this);
34499 this.editor.tree = this;
34500 this.editor = Roo.factory(this.editor, Roo.tree);
34503 if (this.selModel) {
34504 this.selModel = Roo.factory(this.selModel, Roo.tree);
34508 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34509 rootVisible : true,
34510 animate: Roo.enableFx,
34513 hlDrop : Roo.enableFx,
34517 rendererTip: false,
34519 restrictExpand : function(node){
34520 var p = node.parentNode;
34522 if(p.expandedChild && p.expandedChild.parentNode == p){
34523 p.expandedChild.collapse();
34525 p.expandedChild = node;
34529 // private override
34530 setRootNode : function(node){
34531 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34532 if(!this.rootVisible){
34533 node.ui = new Roo.tree.RootTreeNodeUI(node);
34539 * Returns the container element for this TreePanel
34541 getEl : function(){
34546 * Returns the default TreeLoader for this TreePanel
34548 getLoader : function(){
34549 return this.loader;
34555 expandAll : function(){
34556 this.root.expand(true);
34560 * Collapse all nodes
34562 collapseAll : function(){
34563 this.root.collapse(true);
34567 * Returns the selection model used by this TreePanel
34569 getSelectionModel : function(){
34570 if(!this.selModel){
34571 this.selModel = new Roo.tree.DefaultSelectionModel();
34573 return this.selModel;
34577 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34578 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34579 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34582 getChecked : function(a, startNode){
34583 startNode = startNode || this.root;
34585 var f = function(){
34586 if(this.attributes.checked){
34587 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34590 startNode.cascade(f);
34595 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34596 * @param {String} path
34597 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34598 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34599 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34601 expandPath : function(path, attr, callback){
34602 attr = attr || "id";
34603 var keys = path.split(this.pathSeparator);
34604 var curNode = this.root;
34605 if(curNode.attributes[attr] != keys[1]){ // invalid root
34607 callback(false, null);
34612 var f = function(){
34613 if(++index == keys.length){
34615 callback(true, curNode);
34619 var c = curNode.findChild(attr, keys[index]);
34622 callback(false, curNode);
34627 c.expand(false, false, f);
34629 curNode.expand(false, false, f);
34633 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34634 * @param {String} path
34635 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34636 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34637 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34639 selectPath : function(path, attr, callback){
34640 attr = attr || "id";
34641 var keys = path.split(this.pathSeparator);
34642 var v = keys.pop();
34643 if(keys.length > 0){
34644 var f = function(success, node){
34645 if(success && node){
34646 var n = node.findChild(attr, v);
34652 }else if(callback){
34653 callback(false, n);
34657 callback(false, n);
34661 this.expandPath(keys.join(this.pathSeparator), attr, f);
34663 this.root.select();
34665 callback(true, this.root);
34670 getTreeEl : function(){
34675 * Trigger rendering of this TreePanel
34677 render : function(){
34678 if (this.innerCt) {
34679 return this; // stop it rendering more than once!!
34682 this.innerCt = this.el.createChild({tag:"ul",
34683 cls:"x-tree-root-ct " +
34684 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34686 if(this.containerScroll){
34687 Roo.dd.ScrollManager.register(this.el);
34689 if((this.enableDD || this.enableDrop) && !this.dropZone){
34691 * The dropZone used by this tree if drop is enabled
34692 * @type Roo.tree.TreeDropZone
34694 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34695 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34698 if((this.enableDD || this.enableDrag) && !this.dragZone){
34700 * The dragZone used by this tree if drag is enabled
34701 * @type Roo.tree.TreeDragZone
34703 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34704 ddGroup: this.ddGroup || "TreeDD",
34705 scroll: this.ddScroll
34708 this.getSelectionModel().init(this);
34710 Roo.log("ROOT not set in tree");
34713 this.root.render();
34714 if(!this.rootVisible){
34715 this.root.renderChildren();
34721 * Ext JS Library 1.1.1
34722 * Copyright(c) 2006-2007, Ext JS, LLC.
34724 * Originally Released Under LGPL - original licence link has changed is not relivant.
34727 * <script type="text/javascript">
34732 * @class Roo.tree.DefaultSelectionModel
34733 * @extends Roo.util.Observable
34734 * The default single selection for a TreePanel.
34735 * @param {Object} cfg Configuration
34737 Roo.tree.DefaultSelectionModel = function(cfg){
34738 this.selNode = null;
34744 * @event selectionchange
34745 * Fires when the selected node changes
34746 * @param {DefaultSelectionModel} this
34747 * @param {TreeNode} node the new selection
34749 "selectionchange" : true,
34752 * @event beforeselect
34753 * Fires before the selected node changes, return false to cancel the change
34754 * @param {DefaultSelectionModel} this
34755 * @param {TreeNode} node the new selection
34756 * @param {TreeNode} node the old selection
34758 "beforeselect" : true
34761 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34764 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34765 init : function(tree){
34767 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34768 tree.on("click", this.onNodeClick, this);
34771 onNodeClick : function(node, e){
34772 if (e.ctrlKey && this.selNode == node) {
34773 this.unselect(node);
34781 * @param {TreeNode} node The node to select
34782 * @return {TreeNode} The selected node
34784 select : function(node){
34785 var last = this.selNode;
34786 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34788 last.ui.onSelectedChange(false);
34790 this.selNode = node;
34791 node.ui.onSelectedChange(true);
34792 this.fireEvent("selectionchange", this, node, last);
34799 * @param {TreeNode} node The node to unselect
34801 unselect : function(node){
34802 if(this.selNode == node){
34803 this.clearSelections();
34808 * Clear all selections
34810 clearSelections : function(){
34811 var n = this.selNode;
34813 n.ui.onSelectedChange(false);
34814 this.selNode = null;
34815 this.fireEvent("selectionchange", this, null);
34821 * Get the selected node
34822 * @return {TreeNode} The selected node
34824 getSelectedNode : function(){
34825 return this.selNode;
34829 * Returns true if the node is selected
34830 * @param {TreeNode} node The node to check
34831 * @return {Boolean}
34833 isSelected : function(node){
34834 return this.selNode == node;
34838 * Selects the node above the selected node in the tree, intelligently walking the nodes
34839 * @return TreeNode The new selection
34841 selectPrevious : function(){
34842 var s = this.selNode || this.lastSelNode;
34846 var ps = s.previousSibling;
34848 if(!ps.isExpanded() || ps.childNodes.length < 1){
34849 return this.select(ps);
34851 var lc = ps.lastChild;
34852 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34855 return this.select(lc);
34857 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34858 return this.select(s.parentNode);
34864 * Selects the node above the selected node in the tree, intelligently walking the nodes
34865 * @return TreeNode The new selection
34867 selectNext : function(){
34868 var s = this.selNode || this.lastSelNode;
34872 if(s.firstChild && s.isExpanded()){
34873 return this.select(s.firstChild);
34874 }else if(s.nextSibling){
34875 return this.select(s.nextSibling);
34876 }else if(s.parentNode){
34878 s.parentNode.bubble(function(){
34879 if(this.nextSibling){
34880 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34889 onKeyDown : function(e){
34890 var s = this.selNode || this.lastSelNode;
34891 // undesirable, but required
34896 var k = e.getKey();
34904 this.selectPrevious();
34907 e.preventDefault();
34908 if(s.hasChildNodes()){
34909 if(!s.isExpanded()){
34911 }else if(s.firstChild){
34912 this.select(s.firstChild, e);
34917 e.preventDefault();
34918 if(s.hasChildNodes() && s.isExpanded()){
34920 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34921 this.select(s.parentNode, e);
34929 * @class Roo.tree.MultiSelectionModel
34930 * @extends Roo.util.Observable
34931 * Multi selection for a TreePanel.
34932 * @param {Object} cfg Configuration
34934 Roo.tree.MultiSelectionModel = function(){
34935 this.selNodes = [];
34939 * @event selectionchange
34940 * Fires when the selected nodes change
34941 * @param {MultiSelectionModel} this
34942 * @param {Array} nodes Array of the selected nodes
34944 "selectionchange" : true
34946 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34950 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34951 init : function(tree){
34953 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34954 tree.on("click", this.onNodeClick, this);
34957 onNodeClick : function(node, e){
34958 this.select(node, e, e.ctrlKey);
34963 * @param {TreeNode} node The node to select
34964 * @param {EventObject} e (optional) An event associated with the selection
34965 * @param {Boolean} keepExisting True to retain existing selections
34966 * @return {TreeNode} The selected node
34968 select : function(node, e, keepExisting){
34969 if(keepExisting !== true){
34970 this.clearSelections(true);
34972 if(this.isSelected(node)){
34973 this.lastSelNode = node;
34976 this.selNodes.push(node);
34977 this.selMap[node.id] = node;
34978 this.lastSelNode = node;
34979 node.ui.onSelectedChange(true);
34980 this.fireEvent("selectionchange", this, this.selNodes);
34986 * @param {TreeNode} node The node to unselect
34988 unselect : function(node){
34989 if(this.selMap[node.id]){
34990 node.ui.onSelectedChange(false);
34991 var sn = this.selNodes;
34994 index = sn.indexOf(node);
34996 for(var i = 0, len = sn.length; i < len; i++){
35004 this.selNodes.splice(index, 1);
35006 delete this.selMap[node.id];
35007 this.fireEvent("selectionchange", this, this.selNodes);
35012 * Clear all selections
35014 clearSelections : function(suppressEvent){
35015 var sn = this.selNodes;
35017 for(var i = 0, len = sn.length; i < len; i++){
35018 sn[i].ui.onSelectedChange(false);
35020 this.selNodes = [];
35022 if(suppressEvent !== true){
35023 this.fireEvent("selectionchange", this, this.selNodes);
35029 * Returns true if the node is selected
35030 * @param {TreeNode} node The node to check
35031 * @return {Boolean}
35033 isSelected : function(node){
35034 return this.selMap[node.id] ? true : false;
35038 * Returns an array of the selected nodes
35041 getSelectedNodes : function(){
35042 return this.selNodes;
35045 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35047 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35049 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35052 * Ext JS Library 1.1.1
35053 * Copyright(c) 2006-2007, Ext JS, LLC.
35055 * Originally Released Under LGPL - original licence link has changed is not relivant.
35058 * <script type="text/javascript">
35062 * @class Roo.tree.TreeNode
35063 * @extends Roo.data.Node
35064 * @cfg {String} text The text for this node
35065 * @cfg {Boolean} expanded true to start the node expanded
35066 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35067 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35068 * @cfg {Boolean} disabled true to start the node disabled
35069 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35070 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35071 * @cfg {String} cls A css class to be added to the node
35072 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35073 * @cfg {String} href URL of the link used for the node (defaults to #)
35074 * @cfg {String} hrefTarget target frame for the link
35075 * @cfg {String} qtip An Ext QuickTip for the node
35076 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35077 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35078 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35079 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35080 * (defaults to undefined with no checkbox rendered)
35082 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35084 Roo.tree.TreeNode = function(attributes){
35085 attributes = attributes || {};
35086 if(typeof attributes == "string"){
35087 attributes = {text: attributes};
35089 this.childrenRendered = false;
35090 this.rendered = false;
35091 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35092 this.expanded = attributes.expanded === true;
35093 this.isTarget = attributes.isTarget !== false;
35094 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35095 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35098 * Read-only. The text for this node. To change it use setText().
35101 this.text = attributes.text;
35103 * True if this node is disabled.
35106 this.disabled = attributes.disabled === true;
35110 * @event textchange
35111 * Fires when the text for this node is changed
35112 * @param {Node} this This node
35113 * @param {String} text The new text
35114 * @param {String} oldText The old text
35116 "textchange" : true,
35118 * @event beforeexpand
35119 * Fires before this node is expanded, return false to cancel.
35120 * @param {Node} this This node
35121 * @param {Boolean} deep
35122 * @param {Boolean} anim
35124 "beforeexpand" : true,
35126 * @event beforecollapse
35127 * Fires before this node is collapsed, return false to cancel.
35128 * @param {Node} this This node
35129 * @param {Boolean} deep
35130 * @param {Boolean} anim
35132 "beforecollapse" : true,
35135 * Fires when this node is expanded
35136 * @param {Node} this This node
35140 * @event disabledchange
35141 * Fires when the disabled status of this node changes
35142 * @param {Node} this This node
35143 * @param {Boolean} disabled
35145 "disabledchange" : true,
35148 * Fires when this node is collapsed
35149 * @param {Node} this This node
35153 * @event beforeclick
35154 * Fires before click processing. Return false to cancel the default action.
35155 * @param {Node} this This node
35156 * @param {Roo.EventObject} e The event object
35158 "beforeclick":true,
35160 * @event checkchange
35161 * Fires when a node with a checkbox's checked property changes
35162 * @param {Node} this This node
35163 * @param {Boolean} checked
35165 "checkchange":true,
35168 * Fires when this node is clicked
35169 * @param {Node} this This node
35170 * @param {Roo.EventObject} e The event object
35175 * Fires when this node is double clicked
35176 * @param {Node} this This node
35177 * @param {Roo.EventObject} e The event object
35181 * @event contextmenu
35182 * Fires when this node is right clicked
35183 * @param {Node} this This node
35184 * @param {Roo.EventObject} e The event object
35186 "contextmenu":true,
35188 * @event beforechildrenrendered
35189 * Fires right before the child nodes for this node are rendered
35190 * @param {Node} this This node
35192 "beforechildrenrendered":true
35195 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35198 * Read-only. The UI for this node
35201 this.ui = new uiClass(this);
35203 // finally support items[]
35204 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35209 Roo.each(this.attributes.items, function(c) {
35210 this.appendChild(Roo.factory(c,Roo.Tree));
35212 delete this.attributes.items;
35217 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35218 preventHScroll: true,
35220 * Returns true if this node is expanded
35221 * @return {Boolean}
35223 isExpanded : function(){
35224 return this.expanded;
35228 * Returns the UI object for this node
35229 * @return {TreeNodeUI}
35231 getUI : function(){
35235 // private override
35236 setFirstChild : function(node){
35237 var of = this.firstChild;
35238 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35239 if(this.childrenRendered && of && node != of){
35240 of.renderIndent(true, true);
35243 this.renderIndent(true, true);
35247 // private override
35248 setLastChild : function(node){
35249 var ol = this.lastChild;
35250 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35251 if(this.childrenRendered && ol && node != ol){
35252 ol.renderIndent(true, true);
35255 this.renderIndent(true, true);
35259 // these methods are overridden to provide lazy rendering support
35260 // private override
35261 appendChild : function()
35263 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35264 if(node && this.childrenRendered){
35267 this.ui.updateExpandIcon();
35271 // private override
35272 removeChild : function(node){
35273 this.ownerTree.getSelectionModel().unselect(node);
35274 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35275 // if it's been rendered remove dom node
35276 if(this.childrenRendered){
35279 if(this.childNodes.length < 1){
35280 this.collapse(false, false);
35282 this.ui.updateExpandIcon();
35284 if(!this.firstChild) {
35285 this.childrenRendered = false;
35290 // private override
35291 insertBefore : function(node, refNode){
35292 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35293 if(newNode && refNode && this.childrenRendered){
35296 this.ui.updateExpandIcon();
35301 * Sets the text for this node
35302 * @param {String} text
35304 setText : function(text){
35305 var oldText = this.text;
35307 this.attributes.text = text;
35308 if(this.rendered){ // event without subscribing
35309 this.ui.onTextChange(this, text, oldText);
35311 this.fireEvent("textchange", this, text, oldText);
35315 * Triggers selection of this node
35317 select : function(){
35318 this.getOwnerTree().getSelectionModel().select(this);
35322 * Triggers deselection of this node
35324 unselect : function(){
35325 this.getOwnerTree().getSelectionModel().unselect(this);
35329 * Returns true if this node is selected
35330 * @return {Boolean}
35332 isSelected : function(){
35333 return this.getOwnerTree().getSelectionModel().isSelected(this);
35337 * Expand this node.
35338 * @param {Boolean} deep (optional) True to expand all children as well
35339 * @param {Boolean} anim (optional) false to cancel the default animation
35340 * @param {Function} callback (optional) A callback to be called when
35341 * expanding this node completes (does not wait for deep expand to complete).
35342 * Called with 1 parameter, this node.
35344 expand : function(deep, anim, callback){
35345 if(!this.expanded){
35346 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35349 if(!this.childrenRendered){
35350 this.renderChildren();
35352 this.expanded = true;
35354 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35355 this.ui.animExpand(function(){
35356 this.fireEvent("expand", this);
35357 if(typeof callback == "function"){
35361 this.expandChildNodes(true);
35363 }.createDelegate(this));
35367 this.fireEvent("expand", this);
35368 if(typeof callback == "function"){
35373 if(typeof callback == "function"){
35378 this.expandChildNodes(true);
35382 isHiddenRoot : function(){
35383 return this.isRoot && !this.getOwnerTree().rootVisible;
35387 * Collapse this node.
35388 * @param {Boolean} deep (optional) True to collapse all children as well
35389 * @param {Boolean} anim (optional) false to cancel the default animation
35391 collapse : function(deep, anim){
35392 if(this.expanded && !this.isHiddenRoot()){
35393 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35396 this.expanded = false;
35397 if((this.getOwnerTree().animate && anim !== false) || anim){
35398 this.ui.animCollapse(function(){
35399 this.fireEvent("collapse", this);
35401 this.collapseChildNodes(true);
35403 }.createDelegate(this));
35406 this.ui.collapse();
35407 this.fireEvent("collapse", this);
35411 var cs = this.childNodes;
35412 for(var i = 0, len = cs.length; i < len; i++) {
35413 cs[i].collapse(true, false);
35419 delayedExpand : function(delay){
35420 if(!this.expandProcId){
35421 this.expandProcId = this.expand.defer(delay, this);
35426 cancelExpand : function(){
35427 if(this.expandProcId){
35428 clearTimeout(this.expandProcId);
35430 this.expandProcId = false;
35434 * Toggles expanded/collapsed state of the node
35436 toggle : function(){
35445 * Ensures all parent nodes are expanded
35447 ensureVisible : function(callback){
35448 var tree = this.getOwnerTree();
35449 tree.expandPath(this.parentNode.getPath(), false, function(){
35450 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35451 Roo.callback(callback);
35452 }.createDelegate(this));
35456 * Expand all child nodes
35457 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35459 expandChildNodes : function(deep){
35460 var cs = this.childNodes;
35461 for(var i = 0, len = cs.length; i < len; i++) {
35462 cs[i].expand(deep);
35467 * Collapse all child nodes
35468 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35470 collapseChildNodes : function(deep){
35471 var cs = this.childNodes;
35472 for(var i = 0, len = cs.length; i < len; i++) {
35473 cs[i].collapse(deep);
35478 * Disables this node
35480 disable : function(){
35481 this.disabled = true;
35483 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35484 this.ui.onDisableChange(this, true);
35486 this.fireEvent("disabledchange", this, true);
35490 * Enables this node
35492 enable : function(){
35493 this.disabled = false;
35494 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35495 this.ui.onDisableChange(this, false);
35497 this.fireEvent("disabledchange", this, false);
35501 renderChildren : function(suppressEvent){
35502 if(suppressEvent !== false){
35503 this.fireEvent("beforechildrenrendered", this);
35505 var cs = this.childNodes;
35506 for(var i = 0, len = cs.length; i < len; i++){
35507 cs[i].render(true);
35509 this.childrenRendered = true;
35513 sort : function(fn, scope){
35514 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35515 if(this.childrenRendered){
35516 var cs = this.childNodes;
35517 for(var i = 0, len = cs.length; i < len; i++){
35518 cs[i].render(true);
35524 render : function(bulkRender){
35525 this.ui.render(bulkRender);
35526 if(!this.rendered){
35527 this.rendered = true;
35529 this.expanded = false;
35530 this.expand(false, false);
35536 renderIndent : function(deep, refresh){
35538 this.ui.childIndent = null;
35540 this.ui.renderIndent();
35541 if(deep === true && this.childrenRendered){
35542 var cs = this.childNodes;
35543 for(var i = 0, len = cs.length; i < len; i++){
35544 cs[i].renderIndent(true, refresh);
35550 * Ext JS Library 1.1.1
35551 * Copyright(c) 2006-2007, Ext JS, LLC.
35553 * Originally Released Under LGPL - original licence link has changed is not relivant.
35556 * <script type="text/javascript">
35560 * @class Roo.tree.AsyncTreeNode
35561 * @extends Roo.tree.TreeNode
35562 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35564 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35566 Roo.tree.AsyncTreeNode = function(config){
35567 this.loaded = false;
35568 this.loading = false;
35569 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35571 * @event beforeload
35572 * Fires before this node is loaded, return false to cancel
35573 * @param {Node} this This node
35575 this.addEvents({'beforeload':true, 'load': true});
35578 * Fires when this node is loaded
35579 * @param {Node} this This node
35582 * The loader used by this node (defaults to using the tree's defined loader)
35587 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35588 expand : function(deep, anim, callback){
35589 if(this.loading){ // if an async load is already running, waiting til it's done
35591 var f = function(){
35592 if(!this.loading){ // done loading
35593 clearInterval(timer);
35594 this.expand(deep, anim, callback);
35596 }.createDelegate(this);
35597 timer = setInterval(f, 200);
35601 if(this.fireEvent("beforeload", this) === false){
35604 this.loading = true;
35605 this.ui.beforeLoad(this);
35606 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35608 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35612 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35616 * Returns true if this node is currently loading
35617 * @return {Boolean}
35619 isLoading : function(){
35620 return this.loading;
35623 loadComplete : function(deep, anim, callback){
35624 this.loading = false;
35625 this.loaded = true;
35626 this.ui.afterLoad(this);
35627 this.fireEvent("load", this);
35628 this.expand(deep, anim, callback);
35632 * Returns true if this node has been loaded
35633 * @return {Boolean}
35635 isLoaded : function(){
35636 return this.loaded;
35639 hasChildNodes : function(){
35640 if(!this.isLeaf() && !this.loaded){
35643 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35648 * Trigger a reload for this node
35649 * @param {Function} callback
35651 reload : function(callback){
35652 this.collapse(false, false);
35653 while(this.firstChild){
35654 this.removeChild(this.firstChild);
35656 this.childrenRendered = false;
35657 this.loaded = false;
35658 if(this.isHiddenRoot()){
35659 this.expanded = false;
35661 this.expand(false, false, callback);
35665 * Ext JS Library 1.1.1
35666 * Copyright(c) 2006-2007, Ext JS, LLC.
35668 * Originally Released Under LGPL - original licence link has changed is not relivant.
35671 * <script type="text/javascript">
35675 * @class Roo.tree.TreeNodeUI
35677 * @param {Object} node The node to render
35678 * The TreeNode UI implementation is separate from the
35679 * tree implementation. Unless you are customizing the tree UI,
35680 * you should never have to use this directly.
35682 Roo.tree.TreeNodeUI = function(node){
35684 this.rendered = false;
35685 this.animating = false;
35686 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35689 Roo.tree.TreeNodeUI.prototype = {
35690 removeChild : function(node){
35692 this.ctNode.removeChild(node.ui.getEl());
35696 beforeLoad : function(){
35697 this.addClass("x-tree-node-loading");
35700 afterLoad : function(){
35701 this.removeClass("x-tree-node-loading");
35704 onTextChange : function(node, text, oldText){
35706 this.textNode.innerHTML = text;
35710 onDisableChange : function(node, state){
35711 this.disabled = state;
35713 this.addClass("x-tree-node-disabled");
35715 this.removeClass("x-tree-node-disabled");
35719 onSelectedChange : function(state){
35722 this.addClass("x-tree-selected");
35725 this.removeClass("x-tree-selected");
35729 onMove : function(tree, node, oldParent, newParent, index, refNode){
35730 this.childIndent = null;
35732 var targetNode = newParent.ui.getContainer();
35733 if(!targetNode){//target not rendered
35734 this.holder = document.createElement("div");
35735 this.holder.appendChild(this.wrap);
35738 var insertBefore = refNode ? refNode.ui.getEl() : null;
35740 targetNode.insertBefore(this.wrap, insertBefore);
35742 targetNode.appendChild(this.wrap);
35744 this.node.renderIndent(true);
35748 addClass : function(cls){
35750 Roo.fly(this.elNode).addClass(cls);
35754 removeClass : function(cls){
35756 Roo.fly(this.elNode).removeClass(cls);
35760 remove : function(){
35762 this.holder = document.createElement("div");
35763 this.holder.appendChild(this.wrap);
35767 fireEvent : function(){
35768 return this.node.fireEvent.apply(this.node, arguments);
35771 initEvents : function(){
35772 this.node.on("move", this.onMove, this);
35773 var E = Roo.EventManager;
35774 var a = this.anchor;
35776 var el = Roo.fly(a, '_treeui');
35778 if(Roo.isOpera){ // opera render bug ignores the CSS
35779 el.setStyle("text-decoration", "none");
35782 el.on("click", this.onClick, this);
35783 el.on("dblclick", this.onDblClick, this);
35786 Roo.EventManager.on(this.checkbox,
35787 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35790 el.on("contextmenu", this.onContextMenu, this);
35792 var icon = Roo.fly(this.iconNode);
35793 icon.on("click", this.onClick, this);
35794 icon.on("dblclick", this.onDblClick, this);
35795 icon.on("contextmenu", this.onContextMenu, this);
35796 E.on(this.ecNode, "click", this.ecClick, this, true);
35798 if(this.node.disabled){
35799 this.addClass("x-tree-node-disabled");
35801 if(this.node.hidden){
35802 this.addClass("x-tree-node-disabled");
35804 var ot = this.node.getOwnerTree();
35805 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35806 if(dd && (!this.node.isRoot || ot.rootVisible)){
35807 Roo.dd.Registry.register(this.elNode, {
35809 handles: this.getDDHandles(),
35815 getDDHandles : function(){
35816 return [this.iconNode, this.textNode];
35821 this.wrap.style.display = "none";
35827 this.wrap.style.display = "";
35831 onContextMenu : function(e){
35832 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35833 e.preventDefault();
35835 this.fireEvent("contextmenu", this.node, e);
35839 onClick : function(e){
35844 if(this.fireEvent("beforeclick", this.node, e) !== false){
35845 if(!this.disabled && this.node.attributes.href){
35846 this.fireEvent("click", this.node, e);
35849 e.preventDefault();
35854 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35855 this.node.toggle();
35858 this.fireEvent("click", this.node, e);
35864 onDblClick : function(e){
35865 e.preventDefault();
35870 this.toggleCheck();
35872 if(!this.animating && this.node.hasChildNodes()){
35873 this.node.toggle();
35875 this.fireEvent("dblclick", this.node, e);
35878 onCheckChange : function(){
35879 var checked = this.checkbox.checked;
35880 this.node.attributes.checked = checked;
35881 this.fireEvent('checkchange', this.node, checked);
35884 ecClick : function(e){
35885 if(!this.animating && this.node.hasChildNodes()){
35886 this.node.toggle();
35890 startDrop : function(){
35891 this.dropping = true;
35894 // delayed drop so the click event doesn't get fired on a drop
35895 endDrop : function(){
35896 setTimeout(function(){
35897 this.dropping = false;
35898 }.createDelegate(this), 50);
35901 expand : function(){
35902 this.updateExpandIcon();
35903 this.ctNode.style.display = "";
35906 focus : function(){
35907 if(!this.node.preventHScroll){
35908 try{this.anchor.focus();
35910 }else if(!Roo.isIE){
35912 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35913 var l = noscroll.scrollLeft;
35914 this.anchor.focus();
35915 noscroll.scrollLeft = l;
35920 toggleCheck : function(value){
35921 var cb = this.checkbox;
35923 cb.checked = (value === undefined ? !cb.checked : value);
35929 this.anchor.blur();
35933 animExpand : function(callback){
35934 var ct = Roo.get(this.ctNode);
35936 if(!this.node.hasChildNodes()){
35937 this.updateExpandIcon();
35938 this.ctNode.style.display = "";
35939 Roo.callback(callback);
35942 this.animating = true;
35943 this.updateExpandIcon();
35946 callback : function(){
35947 this.animating = false;
35948 Roo.callback(callback);
35951 duration: this.node.ownerTree.duration || .25
35955 highlight : function(){
35956 var tree = this.node.getOwnerTree();
35957 Roo.fly(this.wrap).highlight(
35958 tree.hlColor || "C3DAF9",
35959 {endColor: tree.hlBaseColor}
35963 collapse : function(){
35964 this.updateExpandIcon();
35965 this.ctNode.style.display = "none";
35968 animCollapse : function(callback){
35969 var ct = Roo.get(this.ctNode);
35970 ct.enableDisplayMode('block');
35973 this.animating = true;
35974 this.updateExpandIcon();
35977 callback : function(){
35978 this.animating = false;
35979 Roo.callback(callback);
35982 duration: this.node.ownerTree.duration || .25
35986 getContainer : function(){
35987 return this.ctNode;
35990 getEl : function(){
35994 appendDDGhost : function(ghostNode){
35995 ghostNode.appendChild(this.elNode.cloneNode(true));
35998 getDDRepairXY : function(){
35999 return Roo.lib.Dom.getXY(this.iconNode);
36002 onRender : function(){
36006 render : function(bulkRender){
36007 var n = this.node, a = n.attributes;
36008 var targetNode = n.parentNode ?
36009 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
36011 if(!this.rendered){
36012 this.rendered = true;
36014 this.renderElements(n, a, targetNode, bulkRender);
36017 if(this.textNode.setAttributeNS){
36018 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
36020 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
36023 this.textNode.setAttribute("ext:qtip", a.qtip);
36025 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
36028 }else if(a.qtipCfg){
36029 a.qtipCfg.target = Roo.id(this.textNode);
36030 Roo.QuickTips.register(a.qtipCfg);
36033 if(!this.node.expanded){
36034 this.updateExpandIcon();
36037 if(bulkRender === true) {
36038 targetNode.appendChild(this.wrap);
36043 renderElements : function(n, a, targetNode, bulkRender)
36045 // add some indent caching, this helps performance when rendering a large tree
36046 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36047 var t = n.getOwnerTree();
36048 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36049 if (typeof(n.attributes.html) != 'undefined') {
36050 txt = n.attributes.html;
36052 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36053 var cb = typeof a.checked == 'boolean';
36054 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36055 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36056 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36057 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36058 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
36059 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
36060 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
36061 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
36062 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
36063 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36066 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36067 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36068 n.nextSibling.ui.getEl(), buf.join(""));
36070 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36073 this.elNode = this.wrap.childNodes[0];
36074 this.ctNode = this.wrap.childNodes[1];
36075 var cs = this.elNode.childNodes;
36076 this.indentNode = cs[0];
36077 this.ecNode = cs[1];
36078 this.iconNode = cs[2];
36081 this.checkbox = cs[3];
36084 this.anchor = cs[index];
36085 this.textNode = cs[index].firstChild;
36088 getAnchor : function(){
36089 return this.anchor;
36092 getTextEl : function(){
36093 return this.textNode;
36096 getIconEl : function(){
36097 return this.iconNode;
36100 isChecked : function(){
36101 return this.checkbox ? this.checkbox.checked : false;
36104 updateExpandIcon : function(){
36106 var n = this.node, c1, c2;
36107 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36108 var hasChild = n.hasChildNodes();
36112 c1 = "x-tree-node-collapsed";
36113 c2 = "x-tree-node-expanded";
36116 c1 = "x-tree-node-expanded";
36117 c2 = "x-tree-node-collapsed";
36120 this.removeClass("x-tree-node-leaf");
36121 this.wasLeaf = false;
36123 if(this.c1 != c1 || this.c2 != c2){
36124 Roo.fly(this.elNode).replaceClass(c1, c2);
36125 this.c1 = c1; this.c2 = c2;
36128 // this changes non-leafs into leafs if they have no children.
36129 // it's not very rational behaviour..
36131 if(!this.wasLeaf && this.node.leaf){
36132 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36135 this.wasLeaf = true;
36138 var ecc = "x-tree-ec-icon "+cls;
36139 if(this.ecc != ecc){
36140 this.ecNode.className = ecc;
36146 getChildIndent : function(){
36147 if(!this.childIndent){
36151 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36153 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36155 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36160 this.childIndent = buf.join("");
36162 return this.childIndent;
36165 renderIndent : function(){
36168 var p = this.node.parentNode;
36170 indent = p.ui.getChildIndent();
36172 if(this.indentMarkup != indent){ // don't rerender if not required
36173 this.indentNode.innerHTML = indent;
36174 this.indentMarkup = indent;
36176 this.updateExpandIcon();
36181 Roo.tree.RootTreeNodeUI = function(){
36182 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36184 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36185 render : function(){
36186 if(!this.rendered){
36187 var targetNode = this.node.ownerTree.innerCt.dom;
36188 this.node.expanded = true;
36189 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36190 this.wrap = this.ctNode = targetNode.firstChild;
36193 collapse : function(){
36195 expand : function(){
36199 * Ext JS Library 1.1.1
36200 * Copyright(c) 2006-2007, Ext JS, LLC.
36202 * Originally Released Under LGPL - original licence link has changed is not relivant.
36205 * <script type="text/javascript">
36208 * @class Roo.tree.TreeLoader
36209 * @extends Roo.util.Observable
36210 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36211 * nodes from a specified URL. The response must be a javascript Array definition
36212 * who's elements are node definition objects. eg:
36217 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36218 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36225 * The old style respose with just an array is still supported, but not recommended.
36228 * A server request is sent, and child nodes are loaded only when a node is expanded.
36229 * The loading node's id is passed to the server under the parameter name "node" to
36230 * enable the server to produce the correct child nodes.
36232 * To pass extra parameters, an event handler may be attached to the "beforeload"
36233 * event, and the parameters specified in the TreeLoader's baseParams property:
36235 myTreeLoader.on("beforeload", function(treeLoader, node) {
36236 this.baseParams.category = node.attributes.category;
36241 * This would pass an HTTP parameter called "category" to the server containing
36242 * the value of the Node's "category" attribute.
36244 * Creates a new Treeloader.
36245 * @param {Object} config A config object containing config properties.
36247 Roo.tree.TreeLoader = function(config){
36248 this.baseParams = {};
36249 this.requestMethod = "POST";
36250 Roo.apply(this, config);
36255 * @event beforeload
36256 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36257 * @param {Object} This TreeLoader object.
36258 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36259 * @param {Object} callback The callback function specified in the {@link #load} call.
36264 * Fires when the node has been successfuly loaded.
36265 * @param {Object} This TreeLoader object.
36266 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36267 * @param {Object} response The response object containing the data from the server.
36271 * @event loadexception
36272 * Fires if the network request failed.
36273 * @param {Object} This TreeLoader object.
36274 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36275 * @param {Object} response The response object containing the data from the server.
36277 loadexception : true,
36280 * Fires before a node is created, enabling you to return custom Node types
36281 * @param {Object} This TreeLoader object.
36282 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36287 Roo.tree.TreeLoader.superclass.constructor.call(this);
36290 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36292 * @cfg {String} dataUrl The URL from which to request a Json string which
36293 * specifies an array of node definition object representing the child nodes
36297 * @cfg {String} requestMethod either GET or POST
36298 * defaults to POST (due to BC)
36302 * @cfg {Object} baseParams (optional) An object containing properties which
36303 * specify HTTP parameters to be passed to each request for child nodes.
36306 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36307 * created by this loader. If the attributes sent by the server have an attribute in this object,
36308 * they take priority.
36311 * @cfg {Object} uiProviders (optional) An object containing properties which
36313 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36314 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36315 * <i>uiProvider</i> attribute of a returned child node is a string rather
36316 * than a reference to a TreeNodeUI implementation, this that string value
36317 * is used as a property name in the uiProviders object. You can define the provider named
36318 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36323 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36324 * child nodes before loading.
36326 clearOnLoad : true,
36329 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36330 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36331 * Grid query { data : [ .....] }
36336 * @cfg {String} queryParam (optional)
36337 * Name of the query as it will be passed on the querystring (defaults to 'node')
36338 * eg. the request will be ?node=[id]
36345 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36346 * This is called automatically when a node is expanded, but may be used to reload
36347 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36348 * @param {Roo.tree.TreeNode} node
36349 * @param {Function} callback
36351 load : function(node, callback){
36352 if(this.clearOnLoad){
36353 while(node.firstChild){
36354 node.removeChild(node.firstChild);
36357 if(node.attributes.children){ // preloaded json children
36358 var cs = node.attributes.children;
36359 for(var i = 0, len = cs.length; i < len; i++){
36360 node.appendChild(this.createNode(cs[i]));
36362 if(typeof callback == "function"){
36365 }else if(this.dataUrl){
36366 this.requestData(node, callback);
36370 getParams: function(node){
36371 var buf = [], bp = this.baseParams;
36372 for(var key in bp){
36373 if(typeof bp[key] != "function"){
36374 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36377 var n = this.queryParam === false ? 'node' : this.queryParam;
36378 buf.push(n + "=", encodeURIComponent(node.id));
36379 return buf.join("");
36382 requestData : function(node, callback){
36383 if(this.fireEvent("beforeload", this, node, callback) !== false){
36384 this.transId = Roo.Ajax.request({
36385 method:this.requestMethod,
36386 url: this.dataUrl||this.url,
36387 success: this.handleResponse,
36388 failure: this.handleFailure,
36390 argument: {callback: callback, node: node},
36391 params: this.getParams(node)
36394 // if the load is cancelled, make sure we notify
36395 // the node that we are done
36396 if(typeof callback == "function"){
36402 isLoading : function(){
36403 return this.transId ? true : false;
36406 abort : function(){
36407 if(this.isLoading()){
36408 Roo.Ajax.abort(this.transId);
36413 createNode : function(attr)
36415 // apply baseAttrs, nice idea Corey!
36416 if(this.baseAttrs){
36417 Roo.applyIf(attr, this.baseAttrs);
36419 if(this.applyLoader !== false){
36420 attr.loader = this;
36422 // uiProvider = depreciated..
36424 if(typeof(attr.uiProvider) == 'string'){
36425 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36426 /** eval:var:attr */ eval(attr.uiProvider);
36428 if(typeof(this.uiProviders['default']) != 'undefined') {
36429 attr.uiProvider = this.uiProviders['default'];
36432 this.fireEvent('create', this, attr);
36434 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36436 new Roo.tree.TreeNode(attr) :
36437 new Roo.tree.AsyncTreeNode(attr));
36440 processResponse : function(response, node, callback)
36442 var json = response.responseText;
36445 var o = Roo.decode(json);
36447 if (this.root === false && typeof(o.success) != undefined) {
36448 this.root = 'data'; // the default behaviour for list like data..
36451 if (this.root !== false && !o.success) {
36452 // it's a failure condition.
36453 var a = response.argument;
36454 this.fireEvent("loadexception", this, a.node, response);
36455 Roo.log("Load failed - should have a handler really");
36461 if (this.root !== false) {
36465 for(var i = 0, len = o.length; i < len; i++){
36466 var n = this.createNode(o[i]);
36468 node.appendChild(n);
36471 if(typeof callback == "function"){
36472 callback(this, node);
36475 this.handleFailure(response);
36479 handleResponse : function(response){
36480 this.transId = false;
36481 var a = response.argument;
36482 this.processResponse(response, a.node, a.callback);
36483 this.fireEvent("load", this, a.node, response);
36486 handleFailure : function(response)
36488 // should handle failure better..
36489 this.transId = false;
36490 var a = response.argument;
36491 this.fireEvent("loadexception", this, a.node, response);
36492 if(typeof a.callback == "function"){
36493 a.callback(this, a.node);
36498 * Ext JS Library 1.1.1
36499 * Copyright(c) 2006-2007, Ext JS, LLC.
36501 * Originally Released Under LGPL - original licence link has changed is not relivant.
36504 * <script type="text/javascript">
36508 * @class Roo.tree.TreeFilter
36509 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36510 * @param {TreePanel} tree
36511 * @param {Object} config (optional)
36513 Roo.tree.TreeFilter = function(tree, config){
36515 this.filtered = {};
36516 Roo.apply(this, config);
36519 Roo.tree.TreeFilter.prototype = {
36526 * Filter the data by a specific attribute.
36527 * @param {String/RegExp} value Either string that the attribute value
36528 * should start with or a RegExp to test against the attribute
36529 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36530 * @param {TreeNode} startNode (optional) The node to start the filter at.
36532 filter : function(value, attr, startNode){
36533 attr = attr || "text";
36535 if(typeof value == "string"){
36536 var vlen = value.length;
36537 // auto clear empty filter
36538 if(vlen == 0 && this.clearBlank){
36542 value = value.toLowerCase();
36544 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36546 }else if(value.exec){ // regex?
36548 return value.test(n.attributes[attr]);
36551 throw 'Illegal filter type, must be string or regex';
36553 this.filterBy(f, null, startNode);
36557 * Filter by a function. The passed function will be called with each
36558 * node in the tree (or from the startNode). If the function returns true, the node is kept
36559 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36560 * @param {Function} fn The filter function
36561 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36563 filterBy : function(fn, scope, startNode){
36564 startNode = startNode || this.tree.root;
36565 if(this.autoClear){
36568 var af = this.filtered, rv = this.reverse;
36569 var f = function(n){
36570 if(n == startNode){
36576 var m = fn.call(scope || n, n);
36584 startNode.cascade(f);
36587 if(typeof id != "function"){
36589 if(n && n.parentNode){
36590 n.parentNode.removeChild(n);
36598 * Clears the current filter. Note: with the "remove" option
36599 * set a filter cannot be cleared.
36601 clear : function(){
36603 var af = this.filtered;
36605 if(typeof id != "function"){
36612 this.filtered = {};
36617 * Ext JS Library 1.1.1
36618 * Copyright(c) 2006-2007, Ext JS, LLC.
36620 * Originally Released Under LGPL - original licence link has changed is not relivant.
36623 * <script type="text/javascript">
36628 * @class Roo.tree.TreeSorter
36629 * Provides sorting of nodes in a TreePanel
36631 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36632 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36633 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36634 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36635 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36636 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36638 * @param {TreePanel} tree
36639 * @param {Object} config
36641 Roo.tree.TreeSorter = function(tree, config){
36642 Roo.apply(this, config);
36643 tree.on("beforechildrenrendered", this.doSort, this);
36644 tree.on("append", this.updateSort, this);
36645 tree.on("insert", this.updateSort, this);
36647 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36648 var p = this.property || "text";
36649 var sortType = this.sortType;
36650 var fs = this.folderSort;
36651 var cs = this.caseSensitive === true;
36652 var leafAttr = this.leafAttr || 'leaf';
36654 this.sortFn = function(n1, n2){
36656 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36659 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36663 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36664 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36666 return dsc ? +1 : -1;
36668 return dsc ? -1 : +1;
36675 Roo.tree.TreeSorter.prototype = {
36676 doSort : function(node){
36677 node.sort(this.sortFn);
36680 compareNodes : function(n1, n2){
36681 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36684 updateSort : function(tree, node){
36685 if(node.childrenRendered){
36686 this.doSort.defer(1, this, [node]);
36691 * Ext JS Library 1.1.1
36692 * Copyright(c) 2006-2007, Ext JS, LLC.
36694 * Originally Released Under LGPL - original licence link has changed is not relivant.
36697 * <script type="text/javascript">
36700 if(Roo.dd.DropZone){
36702 Roo.tree.TreeDropZone = function(tree, config){
36703 this.allowParentInsert = false;
36704 this.allowContainerDrop = false;
36705 this.appendOnly = false;
36706 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36708 this.lastInsertClass = "x-tree-no-status";
36709 this.dragOverData = {};
36712 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36713 ddGroup : "TreeDD",
36716 expandDelay : 1000,
36718 expandNode : function(node){
36719 if(node.hasChildNodes() && !node.isExpanded()){
36720 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36724 queueExpand : function(node){
36725 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36728 cancelExpand : function(){
36729 if(this.expandProcId){
36730 clearTimeout(this.expandProcId);
36731 this.expandProcId = false;
36735 isValidDropPoint : function(n, pt, dd, e, data){
36736 if(!n || !data){ return false; }
36737 var targetNode = n.node;
36738 var dropNode = data.node;
36739 // default drop rules
36740 if(!(targetNode && targetNode.isTarget && pt)){
36743 if(pt == "append" && targetNode.allowChildren === false){
36746 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36749 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36752 // reuse the object
36753 var overEvent = this.dragOverData;
36754 overEvent.tree = this.tree;
36755 overEvent.target = targetNode;
36756 overEvent.data = data;
36757 overEvent.point = pt;
36758 overEvent.source = dd;
36759 overEvent.rawEvent = e;
36760 overEvent.dropNode = dropNode;
36761 overEvent.cancel = false;
36762 var result = this.tree.fireEvent("nodedragover", overEvent);
36763 return overEvent.cancel === false && result !== false;
36766 getDropPoint : function(e, n, dd)
36770 return tn.allowChildren !== false ? "append" : false; // always append for root
36772 var dragEl = n.ddel;
36773 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36774 var y = Roo.lib.Event.getPageY(e);
36775 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36777 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36778 var noAppend = tn.allowChildren === false;
36779 if(this.appendOnly || tn.parentNode.allowChildren === false){
36780 return noAppend ? false : "append";
36782 var noBelow = false;
36783 if(!this.allowParentInsert){
36784 noBelow = tn.hasChildNodes() && tn.isExpanded();
36786 var q = (b - t) / (noAppend ? 2 : 3);
36787 if(y >= t && y < (t + q)){
36789 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36796 onNodeEnter : function(n, dd, e, data)
36798 this.cancelExpand();
36801 onNodeOver : function(n, dd, e, data)
36804 var pt = this.getDropPoint(e, n, dd);
36807 // auto node expand check
36808 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36809 this.queueExpand(node);
36810 }else if(pt != "append"){
36811 this.cancelExpand();
36814 // set the insert point style on the target node
36815 var returnCls = this.dropNotAllowed;
36816 if(this.isValidDropPoint(n, pt, dd, e, data)){
36821 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36822 cls = "x-tree-drag-insert-above";
36823 }else if(pt == "below"){
36824 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36825 cls = "x-tree-drag-insert-below";
36827 returnCls = "x-tree-drop-ok-append";
36828 cls = "x-tree-drag-append";
36830 if(this.lastInsertClass != cls){
36831 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36832 this.lastInsertClass = cls;
36839 onNodeOut : function(n, dd, e, data){
36841 this.cancelExpand();
36842 this.removeDropIndicators(n);
36845 onNodeDrop : function(n, dd, e, data){
36846 var point = this.getDropPoint(e, n, dd);
36847 var targetNode = n.node;
36848 targetNode.ui.startDrop();
36849 if(!this.isValidDropPoint(n, point, dd, e, data)){
36850 targetNode.ui.endDrop();
36853 // first try to find the drop node
36854 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36857 target: targetNode,
36862 dropNode: dropNode,
36865 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36866 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36867 targetNode.ui.endDrop();
36870 // allow target changing
36871 targetNode = dropEvent.target;
36872 if(point == "append" && !targetNode.isExpanded()){
36873 targetNode.expand(false, null, function(){
36874 this.completeDrop(dropEvent);
36875 }.createDelegate(this));
36877 this.completeDrop(dropEvent);
36882 completeDrop : function(de){
36883 var ns = de.dropNode, p = de.point, t = de.target;
36884 if(!(ns instanceof Array)){
36888 for(var i = 0, len = ns.length; i < len; i++){
36891 t.parentNode.insertBefore(n, t);
36892 }else if(p == "below"){
36893 t.parentNode.insertBefore(n, t.nextSibling);
36899 if(this.tree.hlDrop){
36903 this.tree.fireEvent("nodedrop", de);
36906 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36907 if(this.tree.hlDrop){
36908 dropNode.ui.focus();
36909 dropNode.ui.highlight();
36911 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36914 getTree : function(){
36918 removeDropIndicators : function(n){
36921 Roo.fly(el).removeClass([
36922 "x-tree-drag-insert-above",
36923 "x-tree-drag-insert-below",
36924 "x-tree-drag-append"]);
36925 this.lastInsertClass = "_noclass";
36929 beforeDragDrop : function(target, e, id){
36930 this.cancelExpand();
36934 afterRepair : function(data){
36935 if(data && Roo.enableFx){
36936 data.node.ui.highlight();
36946 * Ext JS Library 1.1.1
36947 * Copyright(c) 2006-2007, Ext JS, LLC.
36949 * Originally Released Under LGPL - original licence link has changed is not relivant.
36952 * <script type="text/javascript">
36956 if(Roo.dd.DragZone){
36957 Roo.tree.TreeDragZone = function(tree, config){
36958 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36962 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36963 ddGroup : "TreeDD",
36965 onBeforeDrag : function(data, e){
36967 return n && n.draggable && !n.disabled;
36971 onInitDrag : function(e){
36972 var data = this.dragData;
36973 this.tree.getSelectionModel().select(data.node);
36974 this.proxy.update("");
36975 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36976 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36979 getRepairXY : function(e, data){
36980 return data.node.ui.getDDRepairXY();
36983 onEndDrag : function(data, e){
36984 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36989 onValidDrop : function(dd, e, id){
36990 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36994 beforeInvalidDrop : function(e, id){
36995 // this scrolls the original position back into view
36996 var sm = this.tree.getSelectionModel();
36997 sm.clearSelections();
36998 sm.select(this.dragData.node);
37003 * Ext JS Library 1.1.1
37004 * Copyright(c) 2006-2007, Ext JS, LLC.
37006 * Originally Released Under LGPL - original licence link has changed is not relivant.
37009 * <script type="text/javascript">
37012 * @class Roo.tree.TreeEditor
37013 * @extends Roo.Editor
37014 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
37015 * as the editor field.
37017 * @param {Object} config (used to be the tree panel.)
37018 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
37020 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
37021 * @cfg {Roo.form.TextField|Object} field The field configuration
37025 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
37028 if (oldconfig) { // old style..
37029 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
37032 tree = config.tree;
37033 config.field = config.field || {};
37034 config.field.xtype = 'TextField';
37035 field = Roo.factory(config.field, Roo.form);
37037 config = config || {};
37042 * @event beforenodeedit
37043 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37044 * false from the handler of this event.
37045 * @param {Editor} this
37046 * @param {Roo.tree.Node} node
37048 "beforenodeedit" : true
37052 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37056 tree.on('beforeclick', this.beforeNodeClick, this);
37057 tree.getTreeEl().on('mousedown', this.hide, this);
37058 this.on('complete', this.updateNode, this);
37059 this.on('beforestartedit', this.fitToTree, this);
37060 this.on('startedit', this.bindScroll, this, {delay:10});
37061 this.on('specialkey', this.onSpecialKey, this);
37064 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
37066 * @cfg {String} alignment
37067 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37073 * @cfg {Boolean} hideEl
37074 * True to hide the bound element while the editor is displayed (defaults to false)
37078 * @cfg {String} cls
37079 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37081 cls: "x-small-editor x-tree-editor",
37083 * @cfg {Boolean} shim
37084 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37090 * @cfg {Number} maxWidth
37091 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37092 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37093 * scroll and client offsets into account prior to each edit.
37100 fitToTree : function(ed, el){
37101 var td = this.tree.getTreeEl().dom, nd = el.dom;
37102 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37103 td.scrollLeft = nd.offsetLeft;
37107 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37108 this.setSize(w, '');
37110 return this.fireEvent('beforenodeedit', this, this.editNode);
37115 triggerEdit : function(node){
37116 this.completeEdit();
37117 this.editNode = node;
37118 this.startEdit(node.ui.textNode, node.text);
37122 bindScroll : function(){
37123 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37127 beforeNodeClick : function(node, e){
37128 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37129 this.lastClick = new Date();
37130 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37132 this.triggerEdit(node);
37139 updateNode : function(ed, value){
37140 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37141 this.editNode.setText(value);
37145 onHide : function(){
37146 Roo.tree.TreeEditor.superclass.onHide.call(this);
37148 this.editNode.ui.focus();
37153 onSpecialKey : function(field, e){
37154 var k = e.getKey();
37158 }else if(k == e.ENTER && !e.hasModifier()){
37160 this.completeEdit();
37163 });//<Script type="text/javascript">
37166 * Ext JS Library 1.1.1
37167 * Copyright(c) 2006-2007, Ext JS, LLC.
37169 * Originally Released Under LGPL - original licence link has changed is not relivant.
37172 * <script type="text/javascript">
37176 * Not documented??? - probably should be...
37179 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37180 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37182 renderElements : function(n, a, targetNode, bulkRender){
37183 //consel.log("renderElements?");
37184 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37186 var t = n.getOwnerTree();
37187 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37189 var cols = t.columns;
37190 var bw = t.borderWidth;
37192 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37193 var cb = typeof a.checked == "boolean";
37194 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37195 var colcls = 'x-t-' + tid + '-c0';
37197 '<li class="x-tree-node">',
37200 '<div class="x-tree-node-el ', a.cls,'">',
37202 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37205 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37206 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37207 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37208 (a.icon ? ' x-tree-node-inline-icon' : ''),
37209 (a.iconCls ? ' '+a.iconCls : ''),
37210 '" unselectable="on" />',
37211 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37212 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37214 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37215 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37216 '<span unselectable="on" qtip="' + tx + '">',
37220 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37221 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37223 for(var i = 1, len = cols.length; i < len; i++){
37225 colcls = 'x-t-' + tid + '-c' +i;
37226 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37227 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37228 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37234 '<div class="x-clear"></div></div>',
37235 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37238 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37239 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37240 n.nextSibling.ui.getEl(), buf.join(""));
37242 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37244 var el = this.wrap.firstChild;
37246 this.elNode = el.firstChild;
37247 this.ranchor = el.childNodes[1];
37248 this.ctNode = this.wrap.childNodes[1];
37249 var cs = el.firstChild.childNodes;
37250 this.indentNode = cs[0];
37251 this.ecNode = cs[1];
37252 this.iconNode = cs[2];
37255 this.checkbox = cs[3];
37258 this.anchor = cs[index];
37260 this.textNode = cs[index].firstChild;
37262 //el.on("click", this.onClick, this);
37263 //el.on("dblclick", this.onDblClick, this);
37266 // console.log(this);
37268 initEvents : function(){
37269 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37272 var a = this.ranchor;
37274 var el = Roo.get(a);
37276 if(Roo.isOpera){ // opera render bug ignores the CSS
37277 el.setStyle("text-decoration", "none");
37280 el.on("click", this.onClick, this);
37281 el.on("dblclick", this.onDblClick, this);
37282 el.on("contextmenu", this.onContextMenu, this);
37286 /*onSelectedChange : function(state){
37289 this.addClass("x-tree-selected");
37292 this.removeClass("x-tree-selected");
37295 addClass : function(cls){
37297 Roo.fly(this.elRow).addClass(cls);
37303 removeClass : function(cls){
37305 Roo.fly(this.elRow).removeClass(cls);
37311 });//<Script type="text/javascript">
37315 * Ext JS Library 1.1.1
37316 * Copyright(c) 2006-2007, Ext JS, LLC.
37318 * Originally Released Under LGPL - original licence link has changed is not relivant.
37321 * <script type="text/javascript">
37326 * @class Roo.tree.ColumnTree
37327 * @extends Roo.data.TreePanel
37328 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37329 * @cfg {int} borderWidth compined right/left border allowance
37331 * @param {String/HTMLElement/Element} el The container element
37332 * @param {Object} config
37334 Roo.tree.ColumnTree = function(el, config)
37336 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37340 * Fire this event on a container when it resizes
37341 * @param {int} w Width
37342 * @param {int} h Height
37346 this.on('resize', this.onResize, this);
37349 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37353 borderWidth: Roo.isBorderBox ? 0 : 2,
37356 render : function(){
37357 // add the header.....
37359 Roo.tree.ColumnTree.superclass.render.apply(this);
37361 this.el.addClass('x-column-tree');
37363 this.headers = this.el.createChild(
37364 {cls:'x-tree-headers'},this.innerCt.dom);
37366 var cols = this.columns, c;
37367 var totalWidth = 0;
37369 var len = cols.length;
37370 for(var i = 0; i < len; i++){
37372 totalWidth += c.width;
37373 this.headEls.push(this.headers.createChild({
37374 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37376 cls:'x-tree-hd-text',
37379 style:'width:'+(c.width-this.borderWidth)+'px;'
37382 this.headers.createChild({cls:'x-clear'});
37383 // prevent floats from wrapping when clipped
37384 this.headers.setWidth(totalWidth);
37385 //this.innerCt.setWidth(totalWidth);
37386 this.innerCt.setStyle({ overflow: 'auto' });
37387 this.onResize(this.width, this.height);
37391 onResize : function(w,h)
37396 this.innerCt.setWidth(this.width);
37397 this.innerCt.setHeight(this.height-20);
37400 var cols = this.columns, c;
37401 var totalWidth = 0;
37403 var len = cols.length;
37404 for(var i = 0; i < len; i++){
37406 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37407 // it's the expander..
37408 expEl = this.headEls[i];
37411 totalWidth += c.width;
37415 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37417 this.headers.setWidth(w-20);
37426 * Ext JS Library 1.1.1
37427 * Copyright(c) 2006-2007, Ext JS, LLC.
37429 * Originally Released Under LGPL - original licence link has changed is not relivant.
37432 * <script type="text/javascript">
37436 * @class Roo.menu.Menu
37437 * @extends Roo.util.Observable
37438 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37439 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37441 * Creates a new Menu
37442 * @param {Object} config Configuration options
37444 Roo.menu.Menu = function(config){
37446 Roo.menu.Menu.superclass.constructor.call(this, config);
37448 this.id = this.id || Roo.id();
37451 * @event beforeshow
37452 * Fires before this menu is displayed
37453 * @param {Roo.menu.Menu} this
37457 * @event beforehide
37458 * Fires before this menu is hidden
37459 * @param {Roo.menu.Menu} this
37464 * Fires after this menu is displayed
37465 * @param {Roo.menu.Menu} this
37470 * Fires after this menu is hidden
37471 * @param {Roo.menu.Menu} this
37476 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37477 * @param {Roo.menu.Menu} this
37478 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37479 * @param {Roo.EventObject} e
37484 * Fires when the mouse is hovering over this menu
37485 * @param {Roo.menu.Menu} this
37486 * @param {Roo.EventObject} e
37487 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37492 * Fires when the mouse exits this menu
37493 * @param {Roo.menu.Menu} this
37494 * @param {Roo.EventObject} e
37495 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37500 * Fires when a menu item contained in this menu is clicked
37501 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37502 * @param {Roo.EventObject} e
37506 if (this.registerMenu) {
37507 Roo.menu.MenuMgr.register(this);
37510 var mis = this.items;
37511 this.items = new Roo.util.MixedCollection();
37513 this.add.apply(this, mis);
37517 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37519 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37523 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37524 * for bottom-right shadow (defaults to "sides")
37528 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37529 * this menu (defaults to "tl-tr?")
37531 subMenuAlign : "tl-tr?",
37533 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37534 * relative to its element of origin (defaults to "tl-bl?")
37536 defaultAlign : "tl-bl?",
37538 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37540 allowOtherMenus : false,
37542 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37544 registerMenu : true,
37549 render : function(){
37553 var el = this.el = new Roo.Layer({
37555 shadow:this.shadow,
37557 parentEl: this.parentEl || document.body,
37561 this.keyNav = new Roo.menu.MenuNav(this);
37564 el.addClass("x-menu-plain");
37567 el.addClass(this.cls);
37569 // generic focus element
37570 this.focusEl = el.createChild({
37571 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37573 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37574 //disabling touch- as it's causing issues ..
37575 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37576 ul.on('click' , this.onClick, this);
37579 ul.on("mouseover", this.onMouseOver, this);
37580 ul.on("mouseout", this.onMouseOut, this);
37581 this.items.each(function(item){
37586 var li = document.createElement("li");
37587 li.className = "x-menu-list-item";
37588 ul.dom.appendChild(li);
37589 item.render(li, this);
37596 autoWidth : function(){
37597 var el = this.el, ul = this.ul;
37601 var w = this.width;
37604 }else if(Roo.isIE){
37605 el.setWidth(this.minWidth);
37606 var t = el.dom.offsetWidth; // force recalc
37607 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37612 delayAutoWidth : function(){
37615 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37617 this.awTask.delay(20);
37622 findTargetItem : function(e){
37623 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37624 if(t && t.menuItemId){
37625 return this.items.get(t.menuItemId);
37630 onClick : function(e){
37631 Roo.log("menu.onClick");
37632 var t = this.findTargetItem(e);
37637 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37638 if(t == this.activeItem && t.shouldDeactivate(e)){
37639 this.activeItem.deactivate();
37640 delete this.activeItem;
37644 this.setActiveItem(t, true);
37652 this.fireEvent("click", this, t, e);
37656 setActiveItem : function(item, autoExpand){
37657 if(item != this.activeItem){
37658 if(this.activeItem){
37659 this.activeItem.deactivate();
37661 this.activeItem = item;
37662 item.activate(autoExpand);
37663 }else if(autoExpand){
37669 tryActivate : function(start, step){
37670 var items = this.items;
37671 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37672 var item = items.get(i);
37673 if(!item.disabled && item.canActivate){
37674 this.setActiveItem(item, false);
37682 onMouseOver : function(e){
37684 if(t = this.findTargetItem(e)){
37685 if(t.canActivate && !t.disabled){
37686 this.setActiveItem(t, true);
37689 this.fireEvent("mouseover", this, e, t);
37693 onMouseOut : function(e){
37695 if(t = this.findTargetItem(e)){
37696 if(t == this.activeItem && t.shouldDeactivate(e)){
37697 this.activeItem.deactivate();
37698 delete this.activeItem;
37701 this.fireEvent("mouseout", this, e, t);
37705 * Read-only. Returns true if the menu is currently displayed, else false.
37708 isVisible : function(){
37709 return this.el && !this.hidden;
37713 * Displays this menu relative to another element
37714 * @param {String/HTMLElement/Roo.Element} element The element to align to
37715 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37716 * the element (defaults to this.defaultAlign)
37717 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37719 show : function(el, pos, parentMenu){
37720 this.parentMenu = parentMenu;
37724 this.fireEvent("beforeshow", this);
37725 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37729 * Displays this menu at a specific xy position
37730 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37731 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37733 showAt : function(xy, parentMenu, /* private: */_e){
37734 this.parentMenu = parentMenu;
37739 this.fireEvent("beforeshow", this);
37740 xy = this.el.adjustForConstraints(xy);
37744 this.hidden = false;
37746 this.fireEvent("show", this);
37749 focus : function(){
37751 this.doFocus.defer(50, this);
37755 doFocus : function(){
37757 this.focusEl.focus();
37762 * Hides this menu and optionally all parent menus
37763 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37765 hide : function(deep){
37766 if(this.el && this.isVisible()){
37767 this.fireEvent("beforehide", this);
37768 if(this.activeItem){
37769 this.activeItem.deactivate();
37770 this.activeItem = null;
37773 this.hidden = true;
37774 this.fireEvent("hide", this);
37776 if(deep === true && this.parentMenu){
37777 this.parentMenu.hide(true);
37782 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37783 * Any of the following are valid:
37785 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37786 * <li>An HTMLElement object which will be converted to a menu item</li>
37787 * <li>A menu item config object that will be created as a new menu item</li>
37788 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37789 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37794 var menu = new Roo.menu.Menu();
37796 // Create a menu item to add by reference
37797 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37799 // Add a bunch of items at once using different methods.
37800 // Only the last item added will be returned.
37801 var item = menu.add(
37802 menuItem, // add existing item by ref
37803 'Dynamic Item', // new TextItem
37804 '-', // new separator
37805 { text: 'Config Item' } // new item by config
37808 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37809 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37812 var a = arguments, l = a.length, item;
37813 for(var i = 0; i < l; i++){
37815 if ((typeof(el) == "object") && el.xtype && el.xns) {
37816 el = Roo.factory(el, Roo.menu);
37819 if(el.render){ // some kind of Item
37820 item = this.addItem(el);
37821 }else if(typeof el == "string"){ // string
37822 if(el == "separator" || el == "-"){
37823 item = this.addSeparator();
37825 item = this.addText(el);
37827 }else if(el.tagName || el.el){ // element
37828 item = this.addElement(el);
37829 }else if(typeof el == "object"){ // must be menu item config?
37830 item = this.addMenuItem(el);
37837 * Returns this menu's underlying {@link Roo.Element} object
37838 * @return {Roo.Element} The element
37840 getEl : function(){
37848 * Adds a separator bar to the menu
37849 * @return {Roo.menu.Item} The menu item that was added
37851 addSeparator : function(){
37852 return this.addItem(new Roo.menu.Separator());
37856 * Adds an {@link Roo.Element} object to the menu
37857 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37858 * @return {Roo.menu.Item} The menu item that was added
37860 addElement : function(el){
37861 return this.addItem(new Roo.menu.BaseItem(el));
37865 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37866 * @param {Roo.menu.Item} item The menu item to add
37867 * @return {Roo.menu.Item} The menu item that was added
37869 addItem : function(item){
37870 this.items.add(item);
37872 var li = document.createElement("li");
37873 li.className = "x-menu-list-item";
37874 this.ul.dom.appendChild(li);
37875 item.render(li, this);
37876 this.delayAutoWidth();
37882 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37883 * @param {Object} config A MenuItem config object
37884 * @return {Roo.menu.Item} The menu item that was added
37886 addMenuItem : function(config){
37887 if(!(config instanceof Roo.menu.Item)){
37888 if(typeof config.checked == "boolean"){ // must be check menu item config?
37889 config = new Roo.menu.CheckItem(config);
37891 config = new Roo.menu.Item(config);
37894 return this.addItem(config);
37898 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37899 * @param {String} text The text to display in the menu item
37900 * @return {Roo.menu.Item} The menu item that was added
37902 addText : function(text){
37903 return this.addItem(new Roo.menu.TextItem({ text : text }));
37907 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37908 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37909 * @param {Roo.menu.Item} item The menu item to add
37910 * @return {Roo.menu.Item} The menu item that was added
37912 insert : function(index, item){
37913 this.items.insert(index, item);
37915 var li = document.createElement("li");
37916 li.className = "x-menu-list-item";
37917 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37918 item.render(li, this);
37919 this.delayAutoWidth();
37925 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37926 * @param {Roo.menu.Item} item The menu item to remove
37928 remove : function(item){
37929 this.items.removeKey(item.id);
37934 * Removes and destroys all items in the menu
37936 removeAll : function(){
37938 while(f = this.items.first()){
37944 // MenuNav is a private utility class used internally by the Menu
37945 Roo.menu.MenuNav = function(menu){
37946 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37947 this.scope = this.menu = menu;
37950 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37951 doRelay : function(e, h){
37952 var k = e.getKey();
37953 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37954 this.menu.tryActivate(0, 1);
37957 return h.call(this.scope || this, e, this.menu);
37960 up : function(e, m){
37961 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37962 m.tryActivate(m.items.length-1, -1);
37966 down : function(e, m){
37967 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37968 m.tryActivate(0, 1);
37972 right : function(e, m){
37974 m.activeItem.expandMenu(true);
37978 left : function(e, m){
37980 if(m.parentMenu && m.parentMenu.activeItem){
37981 m.parentMenu.activeItem.activate();
37985 enter : function(e, m){
37987 e.stopPropagation();
37988 m.activeItem.onClick(e);
37989 m.fireEvent("click", this, m.activeItem);
37995 * Ext JS Library 1.1.1
37996 * Copyright(c) 2006-2007, Ext JS, LLC.
37998 * Originally Released Under LGPL - original licence link has changed is not relivant.
38001 * <script type="text/javascript">
38005 * @class Roo.menu.MenuMgr
38006 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
38009 Roo.menu.MenuMgr = function(){
38010 var menus, active, groups = {}, attached = false, lastShow = new Date();
38012 // private - called when first menu is created
38015 active = new Roo.util.MixedCollection();
38016 Roo.get(document).addKeyListener(27, function(){
38017 if(active.length > 0){
38024 function hideAll(){
38025 if(active && active.length > 0){
38026 var c = active.clone();
38027 c.each(function(m){
38034 function onHide(m){
38036 if(active.length < 1){
38037 Roo.get(document).un("mousedown", onMouseDown);
38043 function onShow(m){
38044 var last = active.last();
38045 lastShow = new Date();
38048 Roo.get(document).on("mousedown", onMouseDown);
38052 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38053 m.parentMenu.activeChild = m;
38054 }else if(last && last.isVisible()){
38055 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
38060 function onBeforeHide(m){
38062 m.activeChild.hide();
38064 if(m.autoHideTimer){
38065 clearTimeout(m.autoHideTimer);
38066 delete m.autoHideTimer;
38071 function onBeforeShow(m){
38072 var pm = m.parentMenu;
38073 if(!pm && !m.allowOtherMenus){
38075 }else if(pm && pm.activeChild && active != m){
38076 pm.activeChild.hide();
38081 function onMouseDown(e){
38082 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38088 function onBeforeCheck(mi, state){
38090 var g = groups[mi.group];
38091 for(var i = 0, l = g.length; i < l; i++){
38093 g[i].setChecked(false);
38102 * Hides all menus that are currently visible
38104 hideAll : function(){
38109 register : function(menu){
38113 menus[menu.id] = menu;
38114 menu.on("beforehide", onBeforeHide);
38115 menu.on("hide", onHide);
38116 menu.on("beforeshow", onBeforeShow);
38117 menu.on("show", onShow);
38118 var g = menu.group;
38119 if(g && menu.events["checkchange"]){
38123 groups[g].push(menu);
38124 menu.on("checkchange", onCheck);
38129 * Returns a {@link Roo.menu.Menu} object
38130 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38131 * be used to generate and return a new Menu instance.
38133 get : function(menu){
38134 if(typeof menu == "string"){ // menu id
38135 return menus[menu];
38136 }else if(menu.events){ // menu instance
38138 }else if(typeof menu.length == 'number'){ // array of menu items?
38139 return new Roo.menu.Menu({items:menu});
38140 }else{ // otherwise, must be a config
38141 return new Roo.menu.Menu(menu);
38146 unregister : function(menu){
38147 delete menus[menu.id];
38148 menu.un("beforehide", onBeforeHide);
38149 menu.un("hide", onHide);
38150 menu.un("beforeshow", onBeforeShow);
38151 menu.un("show", onShow);
38152 var g = menu.group;
38153 if(g && menu.events["checkchange"]){
38154 groups[g].remove(menu);
38155 menu.un("checkchange", onCheck);
38160 registerCheckable : function(menuItem){
38161 var g = menuItem.group;
38166 groups[g].push(menuItem);
38167 menuItem.on("beforecheckchange", onBeforeCheck);
38172 unregisterCheckable : function(menuItem){
38173 var g = menuItem.group;
38175 groups[g].remove(menuItem);
38176 menuItem.un("beforecheckchange", onBeforeCheck);
38182 * Ext JS Library 1.1.1
38183 * Copyright(c) 2006-2007, Ext JS, LLC.
38185 * Originally Released Under LGPL - original licence link has changed is not relivant.
38188 * <script type="text/javascript">
38193 * @class Roo.menu.BaseItem
38194 * @extends Roo.Component
38195 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38196 * management and base configuration options shared by all menu components.
38198 * Creates a new BaseItem
38199 * @param {Object} config Configuration options
38201 Roo.menu.BaseItem = function(config){
38202 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38207 * Fires when this item is clicked
38208 * @param {Roo.menu.BaseItem} this
38209 * @param {Roo.EventObject} e
38214 * Fires when this item is activated
38215 * @param {Roo.menu.BaseItem} this
38219 * @event deactivate
38220 * Fires when this item is deactivated
38221 * @param {Roo.menu.BaseItem} this
38227 this.on("click", this.handler, this.scope, true);
38231 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38233 * @cfg {Function} handler
38234 * A function that will handle the click event of this menu item (defaults to undefined)
38237 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38239 canActivate : false,
38242 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38247 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38249 activeClass : "x-menu-item-active",
38251 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38253 hideOnClick : true,
38255 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38260 ctype: "Roo.menu.BaseItem",
38263 actionMode : "container",
38266 render : function(container, parentMenu){
38267 this.parentMenu = parentMenu;
38268 Roo.menu.BaseItem.superclass.render.call(this, container);
38269 this.container.menuItemId = this.id;
38273 onRender : function(container, position){
38274 this.el = Roo.get(this.el);
38275 container.dom.appendChild(this.el.dom);
38279 onClick : function(e){
38280 if(!this.disabled && this.fireEvent("click", this, e) !== false
38281 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38282 this.handleClick(e);
38289 activate : function(){
38293 var li = this.container;
38294 li.addClass(this.activeClass);
38295 this.region = li.getRegion().adjust(2, 2, -2, -2);
38296 this.fireEvent("activate", this);
38301 deactivate : function(){
38302 this.container.removeClass(this.activeClass);
38303 this.fireEvent("deactivate", this);
38307 shouldDeactivate : function(e){
38308 return !this.region || !this.region.contains(e.getPoint());
38312 handleClick : function(e){
38313 if(this.hideOnClick){
38314 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38319 expandMenu : function(autoActivate){
38324 hideMenu : function(){
38329 * Ext JS Library 1.1.1
38330 * Copyright(c) 2006-2007, Ext JS, LLC.
38332 * Originally Released Under LGPL - original licence link has changed is not relivant.
38335 * <script type="text/javascript">
38339 * @class Roo.menu.Adapter
38340 * @extends Roo.menu.BaseItem
38341 * 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.
38342 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38344 * Creates a new Adapter
38345 * @param {Object} config Configuration options
38347 Roo.menu.Adapter = function(component, config){
38348 Roo.menu.Adapter.superclass.constructor.call(this, config);
38349 this.component = component;
38351 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38353 canActivate : true,
38356 onRender : function(container, position){
38357 this.component.render(container);
38358 this.el = this.component.getEl();
38362 activate : function(){
38366 this.component.focus();
38367 this.fireEvent("activate", this);
38372 deactivate : function(){
38373 this.fireEvent("deactivate", this);
38377 disable : function(){
38378 this.component.disable();
38379 Roo.menu.Adapter.superclass.disable.call(this);
38383 enable : function(){
38384 this.component.enable();
38385 Roo.menu.Adapter.superclass.enable.call(this);
38389 * Ext JS Library 1.1.1
38390 * Copyright(c) 2006-2007, Ext JS, LLC.
38392 * Originally Released Under LGPL - original licence link has changed is not relivant.
38395 * <script type="text/javascript">
38399 * @class Roo.menu.TextItem
38400 * @extends Roo.menu.BaseItem
38401 * Adds a static text string to a menu, usually used as either a heading or group separator.
38402 * Note: old style constructor with text is still supported.
38405 * Creates a new TextItem
38406 * @param {Object} cfg Configuration
38408 Roo.menu.TextItem = function(cfg){
38409 if (typeof(cfg) == 'string') {
38412 Roo.apply(this,cfg);
38415 Roo.menu.TextItem.superclass.constructor.call(this);
38418 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38420 * @cfg {String} text Text to show on item.
38425 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38427 hideOnClick : false,
38429 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38431 itemCls : "x-menu-text",
38434 onRender : function(){
38435 var s = document.createElement("span");
38436 s.className = this.itemCls;
38437 s.innerHTML = this.text;
38439 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38443 * Ext JS Library 1.1.1
38444 * Copyright(c) 2006-2007, Ext JS, LLC.
38446 * Originally Released Under LGPL - original licence link has changed is not relivant.
38449 * <script type="text/javascript">
38453 * @class Roo.menu.Separator
38454 * @extends Roo.menu.BaseItem
38455 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38456 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38458 * @param {Object} config Configuration options
38460 Roo.menu.Separator = function(config){
38461 Roo.menu.Separator.superclass.constructor.call(this, config);
38464 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38466 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38468 itemCls : "x-menu-sep",
38470 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38472 hideOnClick : false,
38475 onRender : function(li){
38476 var s = document.createElement("span");
38477 s.className = this.itemCls;
38478 s.innerHTML = " ";
38480 li.addClass("x-menu-sep-li");
38481 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38485 * Ext JS Library 1.1.1
38486 * Copyright(c) 2006-2007, Ext JS, LLC.
38488 * Originally Released Under LGPL - original licence link has changed is not relivant.
38491 * <script type="text/javascript">
38494 * @class Roo.menu.Item
38495 * @extends Roo.menu.BaseItem
38496 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38497 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38498 * activation and click handling.
38500 * Creates a new Item
38501 * @param {Object} config Configuration options
38503 Roo.menu.Item = function(config){
38504 Roo.menu.Item.superclass.constructor.call(this, config);
38506 this.menu = Roo.menu.MenuMgr.get(this.menu);
38509 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38512 * @cfg {String} text
38513 * The text to show on the menu item.
38517 * @cfg {String} HTML to render in menu
38518 * The text to show on the menu item (HTML version).
38522 * @cfg {String} icon
38523 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38527 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38529 itemCls : "x-menu-item",
38531 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38533 canActivate : true,
38535 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38538 // doc'd in BaseItem
38542 ctype: "Roo.menu.Item",
38545 onRender : function(container, position){
38546 var el = document.createElement("a");
38547 el.hideFocus = true;
38548 el.unselectable = "on";
38549 el.href = this.href || "#";
38550 if(this.hrefTarget){
38551 el.target = this.hrefTarget;
38553 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38555 var html = this.html.length ? this.html : String.format('{0}',this.text);
38557 el.innerHTML = String.format(
38558 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38559 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38561 Roo.menu.Item.superclass.onRender.call(this, container, position);
38565 * Sets the text to display in this menu item
38566 * @param {String} text The text to display
38567 * @param {Boolean} isHTML true to indicate text is pure html.
38569 setText : function(text, isHTML){
38577 var html = this.html.length ? this.html : String.format('{0}',this.text);
38579 this.el.update(String.format(
38580 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38581 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38582 this.parentMenu.autoWidth();
38587 handleClick : function(e){
38588 if(!this.href){ // if no link defined, stop the event automatically
38591 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38595 activate : function(autoExpand){
38596 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38606 shouldDeactivate : function(e){
38607 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38608 if(this.menu && this.menu.isVisible()){
38609 return !this.menu.getEl().getRegion().contains(e.getPoint());
38617 deactivate : function(){
38618 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38623 expandMenu : function(autoActivate){
38624 if(!this.disabled && this.menu){
38625 clearTimeout(this.hideTimer);
38626 delete this.hideTimer;
38627 if(!this.menu.isVisible() && !this.showTimer){
38628 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38629 }else if (this.menu.isVisible() && autoActivate){
38630 this.menu.tryActivate(0, 1);
38636 deferExpand : function(autoActivate){
38637 delete this.showTimer;
38638 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38640 this.menu.tryActivate(0, 1);
38645 hideMenu : function(){
38646 clearTimeout(this.showTimer);
38647 delete this.showTimer;
38648 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38649 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38654 deferHide : function(){
38655 delete this.hideTimer;
38660 * Ext JS Library 1.1.1
38661 * Copyright(c) 2006-2007, Ext JS, LLC.
38663 * Originally Released Under LGPL - original licence link has changed is not relivant.
38666 * <script type="text/javascript">
38670 * @class Roo.menu.CheckItem
38671 * @extends Roo.menu.Item
38672 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38674 * Creates a new CheckItem
38675 * @param {Object} config Configuration options
38677 Roo.menu.CheckItem = function(config){
38678 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38681 * @event beforecheckchange
38682 * Fires before the checked value is set, providing an opportunity to cancel if needed
38683 * @param {Roo.menu.CheckItem} this
38684 * @param {Boolean} checked The new checked value that will be set
38686 "beforecheckchange" : true,
38688 * @event checkchange
38689 * Fires after the checked value has been set
38690 * @param {Roo.menu.CheckItem} this
38691 * @param {Boolean} checked The checked value that was set
38693 "checkchange" : true
38695 if(this.checkHandler){
38696 this.on('checkchange', this.checkHandler, this.scope);
38699 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38701 * @cfg {String} group
38702 * All check items with the same group name will automatically be grouped into a single-select
38703 * radio button group (defaults to '')
38706 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38708 itemCls : "x-menu-item x-menu-check-item",
38710 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38712 groupClass : "x-menu-group-item",
38715 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38716 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38717 * initialized with checked = true will be rendered as checked.
38722 ctype: "Roo.menu.CheckItem",
38725 onRender : function(c){
38726 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38728 this.el.addClass(this.groupClass);
38730 Roo.menu.MenuMgr.registerCheckable(this);
38732 this.checked = false;
38733 this.setChecked(true, true);
38738 destroy : function(){
38740 Roo.menu.MenuMgr.unregisterCheckable(this);
38742 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38746 * Set the checked state of this item
38747 * @param {Boolean} checked The new checked value
38748 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38750 setChecked : function(state, suppressEvent){
38751 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38752 if(this.container){
38753 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38755 this.checked = state;
38756 if(suppressEvent !== true){
38757 this.fireEvent("checkchange", this, state);
38763 handleClick : function(e){
38764 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38765 this.setChecked(!this.checked);
38767 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38771 * Ext JS Library 1.1.1
38772 * Copyright(c) 2006-2007, Ext JS, LLC.
38774 * Originally Released Under LGPL - original licence link has changed is not relivant.
38777 * <script type="text/javascript">
38781 * @class Roo.menu.DateItem
38782 * @extends Roo.menu.Adapter
38783 * A menu item that wraps the {@link Roo.DatPicker} component.
38785 * Creates a new DateItem
38786 * @param {Object} config Configuration options
38788 Roo.menu.DateItem = function(config){
38789 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38790 /** The Roo.DatePicker object @type Roo.DatePicker */
38791 this.picker = this.component;
38792 this.addEvents({select: true});
38794 this.picker.on("render", function(picker){
38795 picker.getEl().swallowEvent("click");
38796 picker.container.addClass("x-menu-date-item");
38799 this.picker.on("select", this.onSelect, this);
38802 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38804 onSelect : function(picker, date){
38805 this.fireEvent("select", this, date, picker);
38806 Roo.menu.DateItem.superclass.handleClick.call(this);
38810 * Ext JS Library 1.1.1
38811 * Copyright(c) 2006-2007, Ext JS, LLC.
38813 * Originally Released Under LGPL - original licence link has changed is not relivant.
38816 * <script type="text/javascript">
38820 * @class Roo.menu.ColorItem
38821 * @extends Roo.menu.Adapter
38822 * A menu item that wraps the {@link Roo.ColorPalette} component.
38824 * Creates a new ColorItem
38825 * @param {Object} config Configuration options
38827 Roo.menu.ColorItem = function(config){
38828 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38829 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38830 this.palette = this.component;
38831 this.relayEvents(this.palette, ["select"]);
38832 if(this.selectHandler){
38833 this.on('select', this.selectHandler, this.scope);
38836 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38838 * Ext JS Library 1.1.1
38839 * Copyright(c) 2006-2007, Ext JS, LLC.
38841 * Originally Released Under LGPL - original licence link has changed is not relivant.
38844 * <script type="text/javascript">
38849 * @class Roo.menu.DateMenu
38850 * @extends Roo.menu.Menu
38851 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38853 * Creates a new DateMenu
38854 * @param {Object} config Configuration options
38856 Roo.menu.DateMenu = function(config){
38857 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38859 var di = new Roo.menu.DateItem(config);
38862 * The {@link Roo.DatePicker} instance for this DateMenu
38865 this.picker = di.picker;
38868 * @param {DatePicker} picker
38869 * @param {Date} date
38871 this.relayEvents(di, ["select"]);
38872 this.on('beforeshow', function(){
38874 this.picker.hideMonthPicker(false);
38878 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38882 * Ext JS Library 1.1.1
38883 * Copyright(c) 2006-2007, Ext JS, LLC.
38885 * Originally Released Under LGPL - original licence link has changed is not relivant.
38888 * <script type="text/javascript">
38893 * @class Roo.menu.ColorMenu
38894 * @extends Roo.menu.Menu
38895 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38897 * Creates a new ColorMenu
38898 * @param {Object} config Configuration options
38900 Roo.menu.ColorMenu = function(config){
38901 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38903 var ci = new Roo.menu.ColorItem(config);
38906 * The {@link Roo.ColorPalette} instance for this ColorMenu
38907 * @type ColorPalette
38909 this.palette = ci.palette;
38912 * @param {ColorPalette} palette
38913 * @param {String} color
38915 this.relayEvents(ci, ["select"]);
38917 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38919 * Ext JS Library 1.1.1
38920 * Copyright(c) 2006-2007, Ext JS, LLC.
38922 * Originally Released Under LGPL - original licence link has changed is not relivant.
38925 * <script type="text/javascript">
38929 * @class Roo.form.TextItem
38930 * @extends Roo.BoxComponent
38931 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38933 * Creates a new TextItem
38934 * @param {Object} config Configuration options
38936 Roo.form.TextItem = function(config){
38937 Roo.form.TextItem.superclass.constructor.call(this, config);
38940 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
38943 * @cfg {String} tag the tag for this item (default div)
38947 * @cfg {String} html the content for this item
38951 getAutoCreate : function()
38964 onRender : function(ct, position)
38966 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
38969 var cfg = this.getAutoCreate();
38971 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38973 if (!cfg.name.length) {
38976 this.el = ct.createChild(cfg, position);
38981 * @param {String} html update the Contents of the element.
38983 setHTML : function(html)
38985 this.fieldEl.dom.innerHTML = html;
38990 * Ext JS Library 1.1.1
38991 * Copyright(c) 2006-2007, Ext JS, LLC.
38993 * Originally Released Under LGPL - original licence link has changed is not relivant.
38996 * <script type="text/javascript">
39000 * @class Roo.form.Field
39001 * @extends Roo.BoxComponent
39002 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39004 * Creates a new Field
39005 * @param {Object} config Configuration options
39007 Roo.form.Field = function(config){
39008 Roo.form.Field.superclass.constructor.call(this, config);
39011 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
39013 * @cfg {String} fieldLabel Label to use when rendering a form.
39016 * @cfg {String} qtip Mouse over tip
39020 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
39022 invalidClass : "x-form-invalid",
39024 * @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")
39026 invalidText : "The value in this field is invalid",
39028 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
39030 focusClass : "x-form-focus",
39032 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
39033 automatic validation (defaults to "keyup").
39035 validationEvent : "keyup",
39037 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
39039 validateOnBlur : true,
39041 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39043 validationDelay : 250,
39045 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39046 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39048 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39050 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39052 fieldClass : "x-form-field",
39054 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
39057 ----------- ----------------------------------------------------------------------
39058 qtip Display a quick tip when the user hovers over the field
39059 title Display a default browser title attribute popup
39060 under Add a block div beneath the field containing the error text
39061 side Add an error icon to the right of the field with a popup on hover
39062 [element id] Add the error text directly to the innerHTML of the specified element
39065 msgTarget : 'qtip',
39067 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39072 * @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.
39077 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39082 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39084 inputType : undefined,
39087 * @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).
39089 tabIndex : undefined,
39092 isFormField : true,
39097 * @property {Roo.Element} fieldEl
39098 * Element Containing the rendered Field (with label etc.)
39101 * @cfg {Mixed} value A value to initialize this field with.
39106 * @cfg {String} name The field's HTML name attribute.
39109 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39112 loadedValue : false,
39116 initComponent : function(){
39117 Roo.form.Field.superclass.initComponent.call(this);
39121 * Fires when this field receives input focus.
39122 * @param {Roo.form.Field} this
39127 * Fires when this field loses input focus.
39128 * @param {Roo.form.Field} this
39132 * @event specialkey
39133 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39134 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39135 * @param {Roo.form.Field} this
39136 * @param {Roo.EventObject} e The event object
39141 * Fires just before the field blurs if the field value has changed.
39142 * @param {Roo.form.Field} this
39143 * @param {Mixed} newValue The new value
39144 * @param {Mixed} oldValue The original value
39149 * Fires after the field has been marked as invalid.
39150 * @param {Roo.form.Field} this
39151 * @param {String} msg The validation message
39156 * Fires after the field has been validated with no errors.
39157 * @param {Roo.form.Field} this
39162 * Fires after the key up
39163 * @param {Roo.form.Field} this
39164 * @param {Roo.EventObject} e The event Object
39171 * Returns the name attribute of the field if available
39172 * @return {String} name The field name
39174 getName: function(){
39175 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39179 onRender : function(ct, position){
39180 Roo.form.Field.superclass.onRender.call(this, ct, position);
39182 var cfg = this.getAutoCreate();
39184 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39186 if (!cfg.name.length) {
39189 if(this.inputType){
39190 cfg.type = this.inputType;
39192 this.el = ct.createChild(cfg, position);
39194 var type = this.el.dom.type;
39196 if(type == 'password'){
39199 this.el.addClass('x-form-'+type);
39202 this.el.dom.readOnly = true;
39204 if(this.tabIndex !== undefined){
39205 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39208 this.el.addClass([this.fieldClass, this.cls]);
39213 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39214 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39215 * @return {Roo.form.Field} this
39217 applyTo : function(target){
39218 this.allowDomMove = false;
39219 this.el = Roo.get(target);
39220 this.render(this.el.dom.parentNode);
39225 initValue : function(){
39226 if(this.value !== undefined){
39227 this.setValue(this.value);
39228 }else if(this.el.dom.value.length > 0){
39229 this.setValue(this.el.dom.value);
39234 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39235 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39237 isDirty : function() {
39238 if(this.disabled) {
39241 return String(this.getValue()) !== String(this.originalValue);
39245 * stores the current value in loadedValue
39247 resetHasChanged : function()
39249 this.loadedValue = String(this.getValue());
39252 * checks the current value against the 'loaded' value.
39253 * Note - will return false if 'resetHasChanged' has not been called first.
39255 hasChanged : function()
39257 if(this.disabled || this.readOnly) {
39260 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39266 afterRender : function(){
39267 Roo.form.Field.superclass.afterRender.call(this);
39272 fireKey : function(e){
39273 //Roo.log('field ' + e.getKey());
39274 if(e.isNavKeyPress()){
39275 this.fireEvent("specialkey", this, e);
39280 * Resets the current field value to the originally loaded value and clears any validation messages
39282 reset : function(){
39283 this.setValue(this.resetValue);
39284 this.originalValue = this.getValue();
39285 this.clearInvalid();
39289 initEvents : function(){
39290 // safari killled keypress - so keydown is now used..
39291 this.el.on("keydown" , this.fireKey, this);
39292 this.el.on("focus", this.onFocus, this);
39293 this.el.on("blur", this.onBlur, this);
39294 this.el.relayEvent('keyup', this);
39296 // reference to original value for reset
39297 this.originalValue = this.getValue();
39298 this.resetValue = this.getValue();
39302 onFocus : function(){
39303 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39304 this.el.addClass(this.focusClass);
39306 if(!this.hasFocus){
39307 this.hasFocus = true;
39308 this.startValue = this.getValue();
39309 this.fireEvent("focus", this);
39313 beforeBlur : Roo.emptyFn,
39316 onBlur : function(){
39318 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39319 this.el.removeClass(this.focusClass);
39321 this.hasFocus = false;
39322 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39325 var v = this.getValue();
39326 if(String(v) !== String(this.startValue)){
39327 this.fireEvent('change', this, v, this.startValue);
39329 this.fireEvent("blur", this);
39333 * Returns whether or not the field value is currently valid
39334 * @param {Boolean} preventMark True to disable marking the field invalid
39335 * @return {Boolean} True if the value is valid, else false
39337 isValid : function(preventMark){
39341 var restore = this.preventMark;
39342 this.preventMark = preventMark === true;
39343 var v = this.validateValue(this.processValue(this.getRawValue()));
39344 this.preventMark = restore;
39349 * Validates the field value
39350 * @return {Boolean} True if the value is valid, else false
39352 validate : function(){
39353 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39354 this.clearInvalid();
39360 processValue : function(value){
39365 // Subclasses should provide the validation implementation by overriding this
39366 validateValue : function(value){
39371 * Mark this field as invalid
39372 * @param {String} msg The validation message
39374 markInvalid : function(msg){
39375 if(!this.rendered || this.preventMark){ // not rendered
39379 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39381 obj.el.addClass(this.invalidClass);
39382 msg = msg || this.invalidText;
39383 switch(this.msgTarget){
39385 obj.el.dom.qtip = msg;
39386 obj.el.dom.qclass = 'x-form-invalid-tip';
39387 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39388 Roo.QuickTips.enable();
39392 this.el.dom.title = msg;
39396 var elp = this.el.findParent('.x-form-element', 5, true);
39397 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39398 this.errorEl.setWidth(elp.getWidth(true)-20);
39400 this.errorEl.update(msg);
39401 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39404 if(!this.errorIcon){
39405 var elp = this.el.findParent('.x-form-element', 5, true);
39406 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39408 this.alignErrorIcon();
39409 this.errorIcon.dom.qtip = msg;
39410 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39411 this.errorIcon.show();
39412 this.on('resize', this.alignErrorIcon, this);
39415 var t = Roo.getDom(this.msgTarget);
39417 t.style.display = this.msgDisplay;
39420 this.fireEvent('invalid', this, msg);
39424 alignErrorIcon : function(){
39425 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39429 * Clear any invalid styles/messages for this field
39431 clearInvalid : function(){
39432 if(!this.rendered || this.preventMark){ // not rendered
39435 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39437 obj.el.removeClass(this.invalidClass);
39438 switch(this.msgTarget){
39440 obj.el.dom.qtip = '';
39443 this.el.dom.title = '';
39447 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39451 if(this.errorIcon){
39452 this.errorIcon.dom.qtip = '';
39453 this.errorIcon.hide();
39454 this.un('resize', this.alignErrorIcon, this);
39458 var t = Roo.getDom(this.msgTarget);
39460 t.style.display = 'none';
39463 this.fireEvent('valid', this);
39467 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39468 * @return {Mixed} value The field value
39470 getRawValue : function(){
39471 var v = this.el.getValue();
39477 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39478 * @return {Mixed} value The field value
39480 getValue : function(){
39481 var v = this.el.getValue();
39487 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39488 * @param {Mixed} value The value to set
39490 setRawValue : function(v){
39491 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39495 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39496 * @param {Mixed} value The value to set
39498 setValue : function(v){
39501 this.el.dom.value = (v === null || v === undefined ? '' : v);
39506 adjustSize : function(w, h){
39507 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39508 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39512 adjustWidth : function(tag, w){
39513 tag = tag.toLowerCase();
39514 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39515 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39516 if(tag == 'input'){
39519 if(tag == 'textarea'){
39522 }else if(Roo.isOpera){
39523 if(tag == 'input'){
39526 if(tag == 'textarea'){
39536 // anything other than normal should be considered experimental
39537 Roo.form.Field.msgFx = {
39539 show: function(msgEl, f){
39540 msgEl.setDisplayed('block');
39543 hide : function(msgEl, f){
39544 msgEl.setDisplayed(false).update('');
39549 show: function(msgEl, f){
39550 msgEl.slideIn('t', {stopFx:true});
39553 hide : function(msgEl, f){
39554 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39559 show: function(msgEl, f){
39560 msgEl.fixDisplay();
39561 msgEl.alignTo(f.el, 'tl-tr');
39562 msgEl.slideIn('l', {stopFx:true});
39565 hide : function(msgEl, f){
39566 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39571 * Ext JS Library 1.1.1
39572 * Copyright(c) 2006-2007, Ext JS, LLC.
39574 * Originally Released Under LGPL - original licence link has changed is not relivant.
39577 * <script type="text/javascript">
39582 * @class Roo.form.TextField
39583 * @extends Roo.form.Field
39584 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39585 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39587 * Creates a new TextField
39588 * @param {Object} config Configuration options
39590 Roo.form.TextField = function(config){
39591 Roo.form.TextField.superclass.constructor.call(this, config);
39595 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39596 * according to the default logic, but this event provides a hook for the developer to apply additional
39597 * logic at runtime to resize the field if needed.
39598 * @param {Roo.form.Field} this This text field
39599 * @param {Number} width The new field width
39605 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39607 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39611 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39615 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39619 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39623 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39627 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39629 disableKeyFilter : false,
39631 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39635 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39639 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39641 maxLength : Number.MAX_VALUE,
39643 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39645 minLengthText : "The minimum length for this field is {0}",
39647 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39649 maxLengthText : "The maximum length for this field is {0}",
39651 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39653 selectOnFocus : false,
39655 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39657 allowLeadingSpace : false,
39659 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39661 blankText : "This field is required",
39663 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39664 * If available, this function will be called only after the basic validators all return true, and will be passed the
39665 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39669 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39670 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39671 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39675 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39679 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39685 initEvents : function()
39687 if (this.emptyText) {
39688 this.el.attr('placeholder', this.emptyText);
39691 Roo.form.TextField.superclass.initEvents.call(this);
39692 if(this.validationEvent == 'keyup'){
39693 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39694 this.el.on('keyup', this.filterValidation, this);
39696 else if(this.validationEvent !== false){
39697 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39700 if(this.selectOnFocus){
39701 this.on("focus", this.preFocus, this);
39703 if (!this.allowLeadingSpace) {
39704 this.on('blur', this.cleanLeadingSpace, this);
39707 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39708 this.el.on("keypress", this.filterKeys, this);
39711 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39712 this.el.on("click", this.autoSize, this);
39714 if(this.el.is('input[type=password]') && Roo.isSafari){
39715 this.el.on('keydown', this.SafariOnKeyDown, this);
39719 processValue : function(value){
39720 if(this.stripCharsRe){
39721 var newValue = value.replace(this.stripCharsRe, '');
39722 if(newValue !== value){
39723 this.setRawValue(newValue);
39730 filterValidation : function(e){
39731 if(!e.isNavKeyPress()){
39732 this.validationTask.delay(this.validationDelay);
39737 onKeyUp : function(e){
39738 if(!e.isNavKeyPress()){
39742 // private - clean the leading white space
39743 cleanLeadingSpace : function(e)
39745 if ( this.inputType == 'file') {
39749 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39752 * Resets the current field value to the originally-loaded value and clears any validation messages.
39755 reset : function(){
39756 Roo.form.TextField.superclass.reset.call(this);
39760 preFocus : function(){
39762 if(this.selectOnFocus){
39763 this.el.dom.select();
39769 filterKeys : function(e){
39770 var k = e.getKey();
39771 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39774 var c = e.getCharCode(), cc = String.fromCharCode(c);
39775 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39778 if(!this.maskRe.test(cc)){
39783 setValue : function(v){
39785 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39791 * Validates a value according to the field's validation rules and marks the field as invalid
39792 * if the validation fails
39793 * @param {Mixed} value The value to validate
39794 * @return {Boolean} True if the value is valid, else false
39796 validateValue : function(value){
39797 if(value.length < 1) { // if it's blank
39798 if(this.allowBlank){
39799 this.clearInvalid();
39802 this.markInvalid(this.blankText);
39806 if(value.length < this.minLength){
39807 this.markInvalid(String.format(this.minLengthText, this.minLength));
39810 if(value.length > this.maxLength){
39811 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39815 var vt = Roo.form.VTypes;
39816 if(!vt[this.vtype](value, this)){
39817 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39821 if(typeof this.validator == "function"){
39822 var msg = this.validator(value);
39824 this.markInvalid(msg);
39828 if(this.regex && !this.regex.test(value)){
39829 this.markInvalid(this.regexText);
39836 * Selects text in this field
39837 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39838 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39840 selectText : function(start, end){
39841 var v = this.getRawValue();
39843 start = start === undefined ? 0 : start;
39844 end = end === undefined ? v.length : end;
39845 var d = this.el.dom;
39846 if(d.setSelectionRange){
39847 d.setSelectionRange(start, end);
39848 }else if(d.createTextRange){
39849 var range = d.createTextRange();
39850 range.moveStart("character", start);
39851 range.moveEnd("character", v.length-end);
39858 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39859 * This only takes effect if grow = true, and fires the autosize event.
39861 autoSize : function(){
39862 if(!this.grow || !this.rendered){
39866 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39869 var v = el.dom.value;
39870 var d = document.createElement('div');
39871 d.appendChild(document.createTextNode(v));
39875 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39876 this.el.setWidth(w);
39877 this.fireEvent("autosize", this, w);
39881 SafariOnKeyDown : function(event)
39883 // this is a workaround for a password hang bug on chrome/ webkit.
39885 var isSelectAll = false;
39887 if(this.el.dom.selectionEnd > 0){
39888 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39890 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39891 event.preventDefault();
39896 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39898 event.preventDefault();
39899 // this is very hacky as keydown always get's upper case.
39901 var cc = String.fromCharCode(event.getCharCode());
39904 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39912 * Ext JS Library 1.1.1
39913 * Copyright(c) 2006-2007, Ext JS, LLC.
39915 * Originally Released Under LGPL - original licence link has changed is not relivant.
39918 * <script type="text/javascript">
39922 * @class Roo.form.Hidden
39923 * @extends Roo.form.TextField
39924 * Simple Hidden element used on forms
39926 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39929 * Creates a new Hidden form element.
39930 * @param {Object} config Configuration options
39935 // easy hidden field...
39936 Roo.form.Hidden = function(config){
39937 Roo.form.Hidden.superclass.constructor.call(this, config);
39940 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39942 inputType: 'hidden',
39945 labelSeparator: '',
39947 itemCls : 'x-form-item-display-none'
39955 * Ext JS Library 1.1.1
39956 * Copyright(c) 2006-2007, Ext JS, LLC.
39958 * Originally Released Under LGPL - original licence link has changed is not relivant.
39961 * <script type="text/javascript">
39965 * @class Roo.form.TriggerField
39966 * @extends Roo.form.TextField
39967 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39968 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39969 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39970 * for which you can provide a custom implementation. For example:
39972 var trigger = new Roo.form.TriggerField();
39973 trigger.onTriggerClick = myTriggerFn;
39974 trigger.applyTo('my-field');
39977 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39978 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39979 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39980 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39982 * Create a new TriggerField.
39983 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39984 * to the base TextField)
39986 Roo.form.TriggerField = function(config){
39987 this.mimicing = false;
39988 Roo.form.TriggerField.superclass.constructor.call(this, config);
39991 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39993 * @cfg {String} triggerClass A CSS class to apply to the trigger
39996 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39997 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39999 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
40001 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
40005 /** @cfg {Boolean} grow @hide */
40006 /** @cfg {Number} growMin @hide */
40007 /** @cfg {Number} growMax @hide */
40013 autoSize: Roo.emptyFn,
40017 deferHeight : true,
40020 actionMode : 'wrap',
40022 onResize : function(w, h){
40023 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
40024 if(typeof w == 'number'){
40025 var x = w - this.trigger.getWidth();
40026 this.el.setWidth(this.adjustWidth('input', x));
40027 this.trigger.setStyle('left', x+'px');
40032 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40035 getResizeEl : function(){
40040 getPositionEl : function(){
40045 alignErrorIcon : function(){
40046 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40050 onRender : function(ct, position){
40051 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40052 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
40053 this.trigger = this.wrap.createChild(this.triggerConfig ||
40054 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
40055 if(this.hideTrigger){
40056 this.trigger.setDisplayed(false);
40058 this.initTrigger();
40060 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
40065 initTrigger : function(){
40066 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40067 this.trigger.addClassOnOver('x-form-trigger-over');
40068 this.trigger.addClassOnClick('x-form-trigger-click');
40072 onDestroy : function(){
40074 this.trigger.removeAllListeners();
40075 this.trigger.remove();
40078 this.wrap.remove();
40080 Roo.form.TriggerField.superclass.onDestroy.call(this);
40084 onFocus : function(){
40085 Roo.form.TriggerField.superclass.onFocus.call(this);
40086 if(!this.mimicing){
40087 this.wrap.addClass('x-trigger-wrap-focus');
40088 this.mimicing = true;
40089 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40090 if(this.monitorTab){
40091 this.el.on("keydown", this.checkTab, this);
40097 checkTab : function(e){
40098 if(e.getKey() == e.TAB){
40099 this.triggerBlur();
40104 onBlur : function(){
40109 mimicBlur : function(e, t){
40110 if(!this.wrap.contains(t) && this.validateBlur()){
40111 this.triggerBlur();
40116 triggerBlur : function(){
40117 this.mimicing = false;
40118 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40119 if(this.monitorTab){
40120 this.el.un("keydown", this.checkTab, this);
40122 this.wrap.removeClass('x-trigger-wrap-focus');
40123 Roo.form.TriggerField.superclass.onBlur.call(this);
40127 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40128 validateBlur : function(e, t){
40133 onDisable : function(){
40134 Roo.form.TriggerField.superclass.onDisable.call(this);
40136 this.wrap.addClass('x-item-disabled');
40141 onEnable : function(){
40142 Roo.form.TriggerField.superclass.onEnable.call(this);
40144 this.wrap.removeClass('x-item-disabled');
40149 onShow : function(){
40150 var ae = this.getActionEl();
40153 ae.dom.style.display = '';
40154 ae.dom.style.visibility = 'visible';
40160 onHide : function(){
40161 var ae = this.getActionEl();
40162 ae.dom.style.display = 'none';
40166 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40167 * by an implementing function.
40169 * @param {EventObject} e
40171 onTriggerClick : Roo.emptyFn
40174 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40175 // to be extended by an implementing class. For an example of implementing this class, see the custom
40176 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40177 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40178 initComponent : function(){
40179 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40181 this.triggerConfig = {
40182 tag:'span', cls:'x-form-twin-triggers', cn:[
40183 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40184 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40188 getTrigger : function(index){
40189 return this.triggers[index];
40192 initTrigger : function(){
40193 var ts = this.trigger.select('.x-form-trigger', true);
40194 this.wrap.setStyle('overflow', 'hidden');
40195 var triggerField = this;
40196 ts.each(function(t, all, index){
40197 t.hide = function(){
40198 var w = triggerField.wrap.getWidth();
40199 this.dom.style.display = 'none';
40200 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40202 t.show = function(){
40203 var w = triggerField.wrap.getWidth();
40204 this.dom.style.display = '';
40205 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40207 var triggerIndex = 'Trigger'+(index+1);
40209 if(this['hide'+triggerIndex]){
40210 t.dom.style.display = 'none';
40212 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40213 t.addClassOnOver('x-form-trigger-over');
40214 t.addClassOnClick('x-form-trigger-click');
40216 this.triggers = ts.elements;
40219 onTrigger1Click : Roo.emptyFn,
40220 onTrigger2Click : Roo.emptyFn
40223 * Ext JS Library 1.1.1
40224 * Copyright(c) 2006-2007, Ext JS, LLC.
40226 * Originally Released Under LGPL - original licence link has changed is not relivant.
40229 * <script type="text/javascript">
40233 * @class Roo.form.TextArea
40234 * @extends Roo.form.TextField
40235 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40236 * support for auto-sizing.
40238 * Creates a new TextArea
40239 * @param {Object} config Configuration options
40241 Roo.form.TextArea = function(config){
40242 Roo.form.TextArea.superclass.constructor.call(this, config);
40243 // these are provided exchanges for backwards compat
40244 // minHeight/maxHeight were replaced by growMin/growMax to be
40245 // compatible with TextField growing config values
40246 if(this.minHeight !== undefined){
40247 this.growMin = this.minHeight;
40249 if(this.maxHeight !== undefined){
40250 this.growMax = this.maxHeight;
40254 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40256 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40260 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40264 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40265 * in the field (equivalent to setting overflow: hidden, defaults to false)
40267 preventScrollbars: false,
40269 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40270 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40274 onRender : function(ct, position){
40276 this.defaultAutoCreate = {
40278 style:"width:300px;height:60px;",
40279 autocomplete: "new-password"
40282 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40284 this.textSizeEl = Roo.DomHelper.append(document.body, {
40285 tag: "pre", cls: "x-form-grow-sizer"
40287 if(this.preventScrollbars){
40288 this.el.setStyle("overflow", "hidden");
40290 this.el.setHeight(this.growMin);
40294 onDestroy : function(){
40295 if(this.textSizeEl){
40296 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40298 Roo.form.TextArea.superclass.onDestroy.call(this);
40302 onKeyUp : function(e){
40303 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40309 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40310 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40312 autoSize : function(){
40313 if(!this.grow || !this.textSizeEl){
40317 var v = el.dom.value;
40318 var ts = this.textSizeEl;
40321 ts.appendChild(document.createTextNode(v));
40324 Roo.fly(ts).setWidth(this.el.getWidth());
40326 v = "  ";
40329 v = v.replace(/\n/g, '<p> </p>');
40331 v += " \n ";
40334 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40335 if(h != this.lastHeight){
40336 this.lastHeight = h;
40337 this.el.setHeight(h);
40338 this.fireEvent("autosize", this, h);
40343 * Ext JS Library 1.1.1
40344 * Copyright(c) 2006-2007, Ext JS, LLC.
40346 * Originally Released Under LGPL - original licence link has changed is not relivant.
40349 * <script type="text/javascript">
40354 * @class Roo.form.NumberField
40355 * @extends Roo.form.TextField
40356 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40358 * Creates a new NumberField
40359 * @param {Object} config Configuration options
40361 Roo.form.NumberField = function(config){
40362 Roo.form.NumberField.superclass.constructor.call(this, config);
40365 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40367 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40369 fieldClass: "x-form-field x-form-num-field",
40371 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40373 allowDecimals : true,
40375 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40377 decimalSeparator : ".",
40379 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40381 decimalPrecision : 2,
40383 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40385 allowNegative : true,
40387 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40389 minValue : Number.NEGATIVE_INFINITY,
40391 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40393 maxValue : Number.MAX_VALUE,
40395 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40397 minText : "The minimum value for this field is {0}",
40399 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40401 maxText : "The maximum value for this field is {0}",
40403 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40404 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40406 nanText : "{0} is not a valid number",
40409 initEvents : function(){
40410 Roo.form.NumberField.superclass.initEvents.call(this);
40411 var allowed = "0123456789";
40412 if(this.allowDecimals){
40413 allowed += this.decimalSeparator;
40415 if(this.allowNegative){
40418 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40419 var keyPress = function(e){
40420 var k = e.getKey();
40421 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40424 var c = e.getCharCode();
40425 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40429 this.el.on("keypress", keyPress, this);
40433 validateValue : function(value){
40434 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40437 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40440 var num = this.parseValue(value);
40442 this.markInvalid(String.format(this.nanText, value));
40445 if(num < this.minValue){
40446 this.markInvalid(String.format(this.minText, this.minValue));
40449 if(num > this.maxValue){
40450 this.markInvalid(String.format(this.maxText, this.maxValue));
40456 getValue : function(){
40457 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40461 parseValue : function(value){
40462 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40463 return isNaN(value) ? '' : value;
40467 fixPrecision : function(value){
40468 var nan = isNaN(value);
40469 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40470 return nan ? '' : value;
40472 return parseFloat(value).toFixed(this.decimalPrecision);
40475 setValue : function(v){
40476 v = this.fixPrecision(v);
40477 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40481 decimalPrecisionFcn : function(v){
40482 return Math.floor(v);
40485 beforeBlur : function(){
40486 var v = this.parseValue(this.getRawValue());
40493 * Ext JS Library 1.1.1
40494 * Copyright(c) 2006-2007, Ext JS, LLC.
40496 * Originally Released Under LGPL - original licence link has changed is not relivant.
40499 * <script type="text/javascript">
40503 * @class Roo.form.DateField
40504 * @extends Roo.form.TriggerField
40505 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40507 * Create a new DateField
40508 * @param {Object} config
40510 Roo.form.DateField = function(config)
40512 Roo.form.DateField.superclass.constructor.call(this, config);
40518 * Fires when a date is selected
40519 * @param {Roo.form.DateField} combo This combo box
40520 * @param {Date} date The date selected
40527 if(typeof this.minValue == "string") {
40528 this.minValue = this.parseDate(this.minValue);
40530 if(typeof this.maxValue == "string") {
40531 this.maxValue = this.parseDate(this.maxValue);
40533 this.ddMatch = null;
40534 if(this.disabledDates){
40535 var dd = this.disabledDates;
40537 for(var i = 0; i < dd.length; i++){
40539 if(i != dd.length-1) {
40543 this.ddMatch = new RegExp(re + ")");
40547 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40549 * @cfg {String} format
40550 * The default date format string which can be overriden for localization support. The format must be
40551 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40555 * @cfg {String} altFormats
40556 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40557 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40559 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40561 * @cfg {Array} disabledDays
40562 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40564 disabledDays : null,
40566 * @cfg {String} disabledDaysText
40567 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40569 disabledDaysText : "Disabled",
40571 * @cfg {Array} disabledDates
40572 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40573 * expression so they are very powerful. Some examples:
40575 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40576 * <li>["03/08", "09/16"] would disable those days for every year</li>
40577 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40578 * <li>["03/../2006"] would disable every day in March 2006</li>
40579 * <li>["^03"] would disable every day in every March</li>
40581 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40582 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40584 disabledDates : null,
40586 * @cfg {String} disabledDatesText
40587 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40589 disabledDatesText : "Disabled",
40591 * @cfg {Date/String} minValue
40592 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40593 * valid format (defaults to null).
40597 * @cfg {Date/String} maxValue
40598 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40599 * valid format (defaults to null).
40603 * @cfg {String} minText
40604 * The error text to display when the date in the cell is before minValue (defaults to
40605 * 'The date in this field must be after {minValue}').
40607 minText : "The date in this field must be equal to or after {0}",
40609 * @cfg {String} maxText
40610 * The error text to display when the date in the cell is after maxValue (defaults to
40611 * 'The date in this field must be before {maxValue}').
40613 maxText : "The date in this field must be equal to or before {0}",
40615 * @cfg {String} invalidText
40616 * The error text to display when the date in the field is invalid (defaults to
40617 * '{value} is not a valid date - it must be in the format {format}').
40619 invalidText : "{0} is not a valid date - it must be in the format {1}",
40621 * @cfg {String} triggerClass
40622 * An additional CSS class used to style the trigger button. The trigger will always get the
40623 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40624 * which displays a calendar icon).
40626 triggerClass : 'x-form-date-trigger',
40630 * @cfg {Boolean} useIso
40631 * if enabled, then the date field will use a hidden field to store the
40632 * real value as iso formated date. default (false)
40636 * @cfg {String/Object} autoCreate
40637 * A DomHelper element spec, or true for a default element spec (defaults to
40638 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40641 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40644 hiddenField: false,
40646 onRender : function(ct, position)
40648 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40650 //this.el.dom.removeAttribute('name');
40651 Roo.log("Changing name?");
40652 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40653 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40655 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40656 // prevent input submission
40657 this.hiddenName = this.name;
40664 validateValue : function(value)
40666 value = this.formatDate(value);
40667 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40668 Roo.log('super failed');
40671 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40674 var svalue = value;
40675 value = this.parseDate(value);
40677 Roo.log('parse date failed' + svalue);
40678 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40681 var time = value.getTime();
40682 if(this.minValue && time < this.minValue.getTime()){
40683 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40686 if(this.maxValue && time > this.maxValue.getTime()){
40687 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40690 if(this.disabledDays){
40691 var day = value.getDay();
40692 for(var i = 0; i < this.disabledDays.length; i++) {
40693 if(day === this.disabledDays[i]){
40694 this.markInvalid(this.disabledDaysText);
40699 var fvalue = this.formatDate(value);
40700 if(this.ddMatch && this.ddMatch.test(fvalue)){
40701 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40708 // Provides logic to override the default TriggerField.validateBlur which just returns true
40709 validateBlur : function(){
40710 return !this.menu || !this.menu.isVisible();
40713 getName: function()
40715 // returns hidden if it's set..
40716 if (!this.rendered) {return ''};
40717 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40722 * Returns the current date value of the date field.
40723 * @return {Date} The date value
40725 getValue : function(){
40727 return this.hiddenField ?
40728 this.hiddenField.value :
40729 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40733 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40734 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40735 * (the default format used is "m/d/y").
40738 //All of these calls set the same date value (May 4, 2006)
40740 //Pass a date object:
40741 var dt = new Date('5/4/06');
40742 dateField.setValue(dt);
40744 //Pass a date string (default format):
40745 dateField.setValue('5/4/06');
40747 //Pass a date string (custom format):
40748 dateField.format = 'Y-m-d';
40749 dateField.setValue('2006-5-4');
40751 * @param {String/Date} date The date or valid date string
40753 setValue : function(date){
40754 if (this.hiddenField) {
40755 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40757 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40758 // make sure the value field is always stored as a date..
40759 this.value = this.parseDate(date);
40765 parseDate : function(value){
40766 if(!value || value instanceof Date){
40769 var v = Date.parseDate(value, this.format);
40770 if (!v && this.useIso) {
40771 v = Date.parseDate(value, 'Y-m-d');
40773 if(!v && this.altFormats){
40774 if(!this.altFormatsArray){
40775 this.altFormatsArray = this.altFormats.split("|");
40777 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40778 v = Date.parseDate(value, this.altFormatsArray[i]);
40785 formatDate : function(date, fmt){
40786 return (!date || !(date instanceof Date)) ?
40787 date : date.dateFormat(fmt || this.format);
40792 select: function(m, d){
40795 this.fireEvent('select', this, d);
40797 show : function(){ // retain focus styling
40801 this.focus.defer(10, this);
40802 var ml = this.menuListeners;
40803 this.menu.un("select", ml.select, this);
40804 this.menu.un("show", ml.show, this);
40805 this.menu.un("hide", ml.hide, this);
40810 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40811 onTriggerClick : function(){
40815 if(this.menu == null){
40816 this.menu = new Roo.menu.DateMenu();
40818 Roo.apply(this.menu.picker, {
40819 showClear: this.allowBlank,
40820 minDate : this.minValue,
40821 maxDate : this.maxValue,
40822 disabledDatesRE : this.ddMatch,
40823 disabledDatesText : this.disabledDatesText,
40824 disabledDays : this.disabledDays,
40825 disabledDaysText : this.disabledDaysText,
40826 format : this.useIso ? 'Y-m-d' : this.format,
40827 minText : String.format(this.minText, this.formatDate(this.minValue)),
40828 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40830 this.menu.on(Roo.apply({}, this.menuListeners, {
40833 this.menu.picker.setValue(this.getValue() || new Date());
40834 this.menu.show(this.el, "tl-bl?");
40837 beforeBlur : function(){
40838 var v = this.parseDate(this.getRawValue());
40848 isDirty : function() {
40849 if(this.disabled) {
40853 if(typeof(this.startValue) === 'undefined'){
40857 return String(this.getValue()) !== String(this.startValue);
40861 cleanLeadingSpace : function(e)
40868 * Ext JS Library 1.1.1
40869 * Copyright(c) 2006-2007, Ext JS, LLC.
40871 * Originally Released Under LGPL - original licence link has changed is not relivant.
40874 * <script type="text/javascript">
40878 * @class Roo.form.MonthField
40879 * @extends Roo.form.TriggerField
40880 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40882 * Create a new MonthField
40883 * @param {Object} config
40885 Roo.form.MonthField = function(config){
40887 Roo.form.MonthField.superclass.constructor.call(this, config);
40893 * Fires when a date is selected
40894 * @param {Roo.form.MonthFieeld} combo This combo box
40895 * @param {Date} date The date selected
40902 if(typeof this.minValue == "string") {
40903 this.minValue = this.parseDate(this.minValue);
40905 if(typeof this.maxValue == "string") {
40906 this.maxValue = this.parseDate(this.maxValue);
40908 this.ddMatch = null;
40909 if(this.disabledDates){
40910 var dd = this.disabledDates;
40912 for(var i = 0; i < dd.length; i++){
40914 if(i != dd.length-1) {
40918 this.ddMatch = new RegExp(re + ")");
40922 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40924 * @cfg {String} format
40925 * The default date format string which can be overriden for localization support. The format must be
40926 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40930 * @cfg {String} altFormats
40931 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40932 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40934 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40936 * @cfg {Array} disabledDays
40937 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40939 disabledDays : [0,1,2,3,4,5,6],
40941 * @cfg {String} disabledDaysText
40942 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40944 disabledDaysText : "Disabled",
40946 * @cfg {Array} disabledDates
40947 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40948 * expression so they are very powerful. Some examples:
40950 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40951 * <li>["03/08", "09/16"] would disable those days for every year</li>
40952 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40953 * <li>["03/../2006"] would disable every day in March 2006</li>
40954 * <li>["^03"] would disable every day in every March</li>
40956 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40957 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40959 disabledDates : null,
40961 * @cfg {String} disabledDatesText
40962 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40964 disabledDatesText : "Disabled",
40966 * @cfg {Date/String} minValue
40967 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40968 * valid format (defaults to null).
40972 * @cfg {Date/String} maxValue
40973 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40974 * valid format (defaults to null).
40978 * @cfg {String} minText
40979 * The error text to display when the date in the cell is before minValue (defaults to
40980 * 'The date in this field must be after {minValue}').
40982 minText : "The date in this field must be equal to or after {0}",
40984 * @cfg {String} maxTextf
40985 * The error text to display when the date in the cell is after maxValue (defaults to
40986 * 'The date in this field must be before {maxValue}').
40988 maxText : "The date in this field must be equal to or before {0}",
40990 * @cfg {String} invalidText
40991 * The error text to display when the date in the field is invalid (defaults to
40992 * '{value} is not a valid date - it must be in the format {format}').
40994 invalidText : "{0} is not a valid date - it must be in the format {1}",
40996 * @cfg {String} triggerClass
40997 * An additional CSS class used to style the trigger button. The trigger will always get the
40998 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40999 * which displays a calendar icon).
41001 triggerClass : 'x-form-date-trigger',
41005 * @cfg {Boolean} useIso
41006 * if enabled, then the date field will use a hidden field to store the
41007 * real value as iso formated date. default (true)
41011 * @cfg {String/Object} autoCreate
41012 * A DomHelper element spec, or true for a default element spec (defaults to
41013 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41016 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
41019 hiddenField: false,
41021 hideMonthPicker : false,
41023 onRender : function(ct, position)
41025 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
41027 this.el.dom.removeAttribute('name');
41028 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41030 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41031 // prevent input submission
41032 this.hiddenName = this.name;
41039 validateValue : function(value)
41041 value = this.formatDate(value);
41042 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41045 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41048 var svalue = value;
41049 value = this.parseDate(value);
41051 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41054 var time = value.getTime();
41055 if(this.minValue && time < this.minValue.getTime()){
41056 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41059 if(this.maxValue && time > this.maxValue.getTime()){
41060 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41063 /*if(this.disabledDays){
41064 var day = value.getDay();
41065 for(var i = 0; i < this.disabledDays.length; i++) {
41066 if(day === this.disabledDays[i]){
41067 this.markInvalid(this.disabledDaysText);
41073 var fvalue = this.formatDate(value);
41074 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41075 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41083 // Provides logic to override the default TriggerField.validateBlur which just returns true
41084 validateBlur : function(){
41085 return !this.menu || !this.menu.isVisible();
41089 * Returns the current date value of the date field.
41090 * @return {Date} The date value
41092 getValue : function(){
41096 return this.hiddenField ?
41097 this.hiddenField.value :
41098 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41102 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41103 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41104 * (the default format used is "m/d/y").
41107 //All of these calls set the same date value (May 4, 2006)
41109 //Pass a date object:
41110 var dt = new Date('5/4/06');
41111 monthField.setValue(dt);
41113 //Pass a date string (default format):
41114 monthField.setValue('5/4/06');
41116 //Pass a date string (custom format):
41117 monthField.format = 'Y-m-d';
41118 monthField.setValue('2006-5-4');
41120 * @param {String/Date} date The date or valid date string
41122 setValue : function(date){
41123 Roo.log('month setValue' + date);
41124 // can only be first of month..
41126 var val = this.parseDate(date);
41128 if (this.hiddenField) {
41129 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41131 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41132 this.value = this.parseDate(date);
41136 parseDate : function(value){
41137 if(!value || value instanceof Date){
41138 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41141 var v = Date.parseDate(value, this.format);
41142 if (!v && this.useIso) {
41143 v = Date.parseDate(value, 'Y-m-d');
41147 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41151 if(!v && this.altFormats){
41152 if(!this.altFormatsArray){
41153 this.altFormatsArray = this.altFormats.split("|");
41155 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41156 v = Date.parseDate(value, this.altFormatsArray[i]);
41163 formatDate : function(date, fmt){
41164 return (!date || !(date instanceof Date)) ?
41165 date : date.dateFormat(fmt || this.format);
41170 select: function(m, d){
41172 this.fireEvent('select', this, d);
41174 show : function(){ // retain focus styling
41178 this.focus.defer(10, this);
41179 var ml = this.menuListeners;
41180 this.menu.un("select", ml.select, this);
41181 this.menu.un("show", ml.show, this);
41182 this.menu.un("hide", ml.hide, this);
41186 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41187 onTriggerClick : function(){
41191 if(this.menu == null){
41192 this.menu = new Roo.menu.DateMenu();
41196 Roo.apply(this.menu.picker, {
41198 showClear: this.allowBlank,
41199 minDate : this.minValue,
41200 maxDate : this.maxValue,
41201 disabledDatesRE : this.ddMatch,
41202 disabledDatesText : this.disabledDatesText,
41204 format : this.useIso ? 'Y-m-d' : this.format,
41205 minText : String.format(this.minText, this.formatDate(this.minValue)),
41206 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41209 this.menu.on(Roo.apply({}, this.menuListeners, {
41217 // hide month picker get's called when we called by 'before hide';
41219 var ignorehide = true;
41220 p.hideMonthPicker = function(disableAnim){
41224 if(this.monthPicker){
41225 Roo.log("hideMonthPicker called");
41226 if(disableAnim === true){
41227 this.monthPicker.hide();
41229 this.monthPicker.slideOut('t', {duration:.2});
41230 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41231 p.fireEvent("select", this, this.value);
41237 Roo.log('picker set value');
41238 Roo.log(this.getValue());
41239 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41240 m.show(this.el, 'tl-bl?');
41241 ignorehide = false;
41242 // this will trigger hideMonthPicker..
41245 // hidden the day picker
41246 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41252 p.showMonthPicker.defer(100, p);
41258 beforeBlur : function(){
41259 var v = this.parseDate(this.getRawValue());
41265 /** @cfg {Boolean} grow @hide */
41266 /** @cfg {Number} growMin @hide */
41267 /** @cfg {Number} growMax @hide */
41274 * Ext JS Library 1.1.1
41275 * Copyright(c) 2006-2007, Ext JS, LLC.
41277 * Originally Released Under LGPL - original licence link has changed is not relivant.
41280 * <script type="text/javascript">
41285 * @class Roo.form.ComboBox
41286 * @extends Roo.form.TriggerField
41287 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41289 * Create a new ComboBox.
41290 * @param {Object} config Configuration options
41292 Roo.form.ComboBox = function(config){
41293 Roo.form.ComboBox.superclass.constructor.call(this, config);
41297 * Fires when the dropdown list is expanded
41298 * @param {Roo.form.ComboBox} combo This combo box
41303 * Fires when the dropdown list is collapsed
41304 * @param {Roo.form.ComboBox} combo This combo box
41308 * @event beforeselect
41309 * Fires before a list item is selected. Return false to cancel the selection.
41310 * @param {Roo.form.ComboBox} combo This combo box
41311 * @param {Roo.data.Record} record The data record returned from the underlying store
41312 * @param {Number} index The index of the selected item in the dropdown list
41314 'beforeselect' : true,
41317 * Fires when a list item is selected
41318 * @param {Roo.form.ComboBox} combo This combo box
41319 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41320 * @param {Number} index The index of the selected item in the dropdown list
41324 * @event beforequery
41325 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41326 * The event object passed has these properties:
41327 * @param {Roo.form.ComboBox} combo This combo box
41328 * @param {String} query The query
41329 * @param {Boolean} forceAll true to force "all" query
41330 * @param {Boolean} cancel true to cancel the query
41331 * @param {Object} e The query event object
41333 'beforequery': true,
41336 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41337 * @param {Roo.form.ComboBox} combo This combo box
41342 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41343 * @param {Roo.form.ComboBox} combo This combo box
41344 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41350 if(this.transform){
41351 this.allowDomMove = false;
41352 var s = Roo.getDom(this.transform);
41353 if(!this.hiddenName){
41354 this.hiddenName = s.name;
41357 this.mode = 'local';
41358 var d = [], opts = s.options;
41359 for(var i = 0, len = opts.length;i < len; i++){
41361 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41363 this.value = value;
41365 d.push([value, o.text]);
41367 this.store = new Roo.data.SimpleStore({
41369 fields: ['value', 'text'],
41372 this.valueField = 'value';
41373 this.displayField = 'text';
41375 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41376 if(!this.lazyRender){
41377 this.target = true;
41378 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41379 s.parentNode.removeChild(s); // remove it
41380 this.render(this.el.parentNode);
41382 s.parentNode.removeChild(s); // remove it
41387 this.store = Roo.factory(this.store, Roo.data);
41390 this.selectedIndex = -1;
41391 if(this.mode == 'local'){
41392 if(config.queryDelay === undefined){
41393 this.queryDelay = 10;
41395 if(config.minChars === undefined){
41401 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41403 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41406 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41407 * rendering into an Roo.Editor, defaults to false)
41410 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41411 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41414 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41417 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41418 * the dropdown list (defaults to undefined, with no header element)
41422 * @cfg {String/Roo.Template} tpl The template to use to render the output
41426 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41428 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41430 listWidth: undefined,
41432 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41433 * mode = 'remote' or 'text' if mode = 'local')
41435 displayField: undefined,
41437 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41438 * mode = 'remote' or 'value' if mode = 'local').
41439 * Note: use of a valueField requires the user make a selection
41440 * in order for a value to be mapped.
41442 valueField: undefined,
41446 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41447 * field's data value (defaults to the underlying DOM element's name)
41449 hiddenName: undefined,
41451 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41455 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41457 selectedClass: 'x-combo-selected',
41459 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41460 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41461 * which displays a downward arrow icon).
41463 triggerClass : 'x-form-arrow-trigger',
41465 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41469 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41470 * anchor positions (defaults to 'tl-bl')
41472 listAlign: 'tl-bl?',
41474 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41478 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41479 * query specified by the allQuery config option (defaults to 'query')
41481 triggerAction: 'query',
41483 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41484 * (defaults to 4, does not apply if editable = false)
41488 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41489 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41493 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41494 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41498 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41499 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41503 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41504 * when editable = true (defaults to false)
41506 selectOnFocus:false,
41508 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41510 queryParam: 'query',
41512 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41513 * when mode = 'remote' (defaults to 'Loading...')
41515 loadingText: 'Loading...',
41517 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41521 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41525 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41526 * traditional select (defaults to true)
41530 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41534 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41538 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41539 * listWidth has a higher value)
41543 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41544 * allow the user to set arbitrary text into the field (defaults to false)
41546 forceSelection:false,
41548 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41549 * if typeAhead = true (defaults to 250)
41551 typeAheadDelay : 250,
41553 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41554 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41556 valueNotFoundText : undefined,
41558 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41560 blockFocus : false,
41563 * @cfg {Boolean} disableClear Disable showing of clear button.
41565 disableClear : false,
41567 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41569 alwaysQuery : false,
41575 // element that contains real text value.. (when hidden is used..)
41578 onRender : function(ct, position)
41580 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41582 if(this.hiddenName){
41583 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41585 this.hiddenField.value =
41586 this.hiddenValue !== undefined ? this.hiddenValue :
41587 this.value !== undefined ? this.value : '';
41589 // prevent input submission
41590 this.el.dom.removeAttribute('name');
41596 this.el.dom.setAttribute('autocomplete', 'off');
41599 var cls = 'x-combo-list';
41601 this.list = new Roo.Layer({
41602 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41605 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41606 this.list.setWidth(lw);
41607 this.list.swallowEvent('mousewheel');
41608 this.assetHeight = 0;
41611 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41612 this.assetHeight += this.header.getHeight();
41615 this.innerList = this.list.createChild({cls:cls+'-inner'});
41616 this.innerList.on('mouseover', this.onViewOver, this);
41617 this.innerList.on('mousemove', this.onViewMove, this);
41618 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41620 if(this.allowBlank && !this.pageSize && !this.disableClear){
41621 this.footer = this.list.createChild({cls:cls+'-ft'});
41622 this.pageTb = new Roo.Toolbar(this.footer);
41626 this.footer = this.list.createChild({cls:cls+'-ft'});
41627 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41628 {pageSize: this.pageSize});
41632 if (this.pageTb && this.allowBlank && !this.disableClear) {
41634 this.pageTb.add(new Roo.Toolbar.Fill(), {
41635 cls: 'x-btn-icon x-btn-clear',
41637 handler: function()
41640 _this.clearValue();
41641 _this.onSelect(false, -1);
41646 this.assetHeight += this.footer.getHeight();
41651 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41654 this.view = new Roo.View(this.innerList, this.tpl, {
41657 selectedClass: this.selectedClass
41660 this.view.on('click', this.onViewClick, this);
41662 this.store.on('beforeload', this.onBeforeLoad, this);
41663 this.store.on('load', this.onLoad, this);
41664 this.store.on('loadexception', this.onLoadException, this);
41666 if(this.resizable){
41667 this.resizer = new Roo.Resizable(this.list, {
41668 pinned:true, handles:'se'
41670 this.resizer.on('resize', function(r, w, h){
41671 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41672 this.listWidth = w;
41673 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41674 this.restrictHeight();
41676 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41678 if(!this.editable){
41679 this.editable = true;
41680 this.setEditable(false);
41684 if (typeof(this.events.add.listeners) != 'undefined') {
41686 this.addicon = this.wrap.createChild(
41687 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41689 this.addicon.on('click', function(e) {
41690 this.fireEvent('add', this);
41693 if (typeof(this.events.edit.listeners) != 'undefined') {
41695 this.editicon = this.wrap.createChild(
41696 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41697 if (this.addicon) {
41698 this.editicon.setStyle('margin-left', '40px');
41700 this.editicon.on('click', function(e) {
41702 // we fire even if inothing is selected..
41703 this.fireEvent('edit', this, this.lastData );
41713 initEvents : function(){
41714 Roo.form.ComboBox.superclass.initEvents.call(this);
41716 this.keyNav = new Roo.KeyNav(this.el, {
41717 "up" : function(e){
41718 this.inKeyMode = true;
41722 "down" : function(e){
41723 if(!this.isExpanded()){
41724 this.onTriggerClick();
41726 this.inKeyMode = true;
41731 "enter" : function(e){
41732 this.onViewClick();
41736 "esc" : function(e){
41740 "tab" : function(e){
41741 this.onViewClick(false);
41742 this.fireEvent("specialkey", this, e);
41748 doRelay : function(foo, bar, hname){
41749 if(hname == 'down' || this.scope.isExpanded()){
41750 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41757 this.queryDelay = Math.max(this.queryDelay || 10,
41758 this.mode == 'local' ? 10 : 250);
41759 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41760 if(this.typeAhead){
41761 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41763 if(this.editable !== false){
41764 this.el.on("keyup", this.onKeyUp, this);
41766 if(this.forceSelection){
41767 this.on('blur', this.doForce, this);
41771 onDestroy : function(){
41773 this.view.setStore(null);
41774 this.view.el.removeAllListeners();
41775 this.view.el.remove();
41776 this.view.purgeListeners();
41779 this.list.destroy();
41782 this.store.un('beforeload', this.onBeforeLoad, this);
41783 this.store.un('load', this.onLoad, this);
41784 this.store.un('loadexception', this.onLoadException, this);
41786 Roo.form.ComboBox.superclass.onDestroy.call(this);
41790 fireKey : function(e){
41791 if(e.isNavKeyPress() && !this.list.isVisible()){
41792 this.fireEvent("specialkey", this, e);
41797 onResize: function(w, h){
41798 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41800 if(typeof w != 'number'){
41801 // we do not handle it!?!?
41804 var tw = this.trigger.getWidth();
41805 tw += this.addicon ? this.addicon.getWidth() : 0;
41806 tw += this.editicon ? this.editicon.getWidth() : 0;
41808 this.el.setWidth( this.adjustWidth('input', x));
41810 this.trigger.setStyle('left', x+'px');
41812 if(this.list && this.listWidth === undefined){
41813 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41814 this.list.setWidth(lw);
41815 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41823 * Allow or prevent the user from directly editing the field text. If false is passed,
41824 * the user will only be able to select from the items defined in the dropdown list. This method
41825 * is the runtime equivalent of setting the 'editable' config option at config time.
41826 * @param {Boolean} value True to allow the user to directly edit the field text
41828 setEditable : function(value){
41829 if(value == this.editable){
41832 this.editable = value;
41834 this.el.dom.setAttribute('readOnly', true);
41835 this.el.on('mousedown', this.onTriggerClick, this);
41836 this.el.addClass('x-combo-noedit');
41838 this.el.dom.setAttribute('readOnly', false);
41839 this.el.un('mousedown', this.onTriggerClick, this);
41840 this.el.removeClass('x-combo-noedit');
41845 onBeforeLoad : function(){
41846 if(!this.hasFocus){
41849 this.innerList.update(this.loadingText ?
41850 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41851 this.restrictHeight();
41852 this.selectedIndex = -1;
41856 onLoad : function(){
41857 if(!this.hasFocus){
41860 if(this.store.getCount() > 0){
41862 this.restrictHeight();
41863 if(this.lastQuery == this.allQuery){
41865 this.el.dom.select();
41867 if(!this.selectByValue(this.value, true)){
41868 this.select(0, true);
41872 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41873 this.taTask.delay(this.typeAheadDelay);
41877 this.onEmptyResults();
41882 onLoadException : function()
41885 Roo.log(this.store.reader.jsonData);
41886 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41887 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41893 onTypeAhead : function(){
41894 if(this.store.getCount() > 0){
41895 var r = this.store.getAt(0);
41896 var newValue = r.data[this.displayField];
41897 var len = newValue.length;
41898 var selStart = this.getRawValue().length;
41899 if(selStart != len){
41900 this.setRawValue(newValue);
41901 this.selectText(selStart, newValue.length);
41907 onSelect : function(record, index){
41908 if(this.fireEvent('beforeselect', this, record, index) !== false){
41909 this.setFromData(index > -1 ? record.data : false);
41911 this.fireEvent('select', this, record, index);
41916 * Returns the currently selected field value or empty string if no value is set.
41917 * @return {String} value The selected value
41919 getValue : function(){
41920 if(this.valueField){
41921 return typeof this.value != 'undefined' ? this.value : '';
41923 return Roo.form.ComboBox.superclass.getValue.call(this);
41927 * Clears any text/value currently set in the field
41929 clearValue : function(){
41930 if(this.hiddenField){
41931 this.hiddenField.value = '';
41934 this.setRawValue('');
41935 this.lastSelectionText = '';
41940 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41941 * will be displayed in the field. If the value does not match the data value of an existing item,
41942 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41943 * Otherwise the field will be blank (although the value will still be set).
41944 * @param {String} value The value to match
41946 setValue : function(v){
41948 if(this.valueField){
41949 var r = this.findRecord(this.valueField, v);
41951 text = r.data[this.displayField];
41952 }else if(this.valueNotFoundText !== undefined){
41953 text = this.valueNotFoundText;
41956 this.lastSelectionText = text;
41957 if(this.hiddenField){
41958 this.hiddenField.value = v;
41960 Roo.form.ComboBox.superclass.setValue.call(this, text);
41964 * @property {Object} the last set data for the element
41969 * Sets the value of the field based on a object which is related to the record format for the store.
41970 * @param {Object} value the value to set as. or false on reset?
41972 setFromData : function(o){
41973 var dv = ''; // display value
41974 var vv = ''; // value value..
41976 if (this.displayField) {
41977 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41979 // this is an error condition!!!
41980 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41983 if(this.valueField){
41984 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41986 if(this.hiddenField){
41987 this.hiddenField.value = vv;
41989 this.lastSelectionText = dv;
41990 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41994 // no hidden field.. - we store the value in 'value', but still display
41995 // display field!!!!
41996 this.lastSelectionText = dv;
41997 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42003 reset : function(){
42004 // overridden so that last data is reset..
42005 this.setValue(this.resetValue);
42006 this.originalValue = this.getValue();
42007 this.clearInvalid();
42008 this.lastData = false;
42010 this.view.clearSelections();
42014 findRecord : function(prop, value){
42016 if(this.store.getCount() > 0){
42017 this.store.each(function(r){
42018 if(r.data[prop] == value){
42028 getName: function()
42030 // returns hidden if it's set..
42031 if (!this.rendered) {return ''};
42032 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42036 onViewMove : function(e, t){
42037 this.inKeyMode = false;
42041 onViewOver : function(e, t){
42042 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42045 var item = this.view.findItemFromChild(t);
42047 var index = this.view.indexOf(item);
42048 this.select(index, false);
42053 onViewClick : function(doFocus)
42055 var index = this.view.getSelectedIndexes()[0];
42056 var r = this.store.getAt(index);
42058 this.onSelect(r, index);
42060 if(doFocus !== false && !this.blockFocus){
42066 restrictHeight : function(){
42067 this.innerList.dom.style.height = '';
42068 var inner = this.innerList.dom;
42069 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42070 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42071 this.list.beginUpdate();
42072 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42073 this.list.alignTo(this.el, this.listAlign);
42074 this.list.endUpdate();
42078 onEmptyResults : function(){
42083 * Returns true if the dropdown list is expanded, else false.
42085 isExpanded : function(){
42086 return this.list.isVisible();
42090 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42091 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42092 * @param {String} value The data value of the item to select
42093 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42094 * selected item if it is not currently in view (defaults to true)
42095 * @return {Boolean} True if the value matched an item in the list, else false
42097 selectByValue : function(v, scrollIntoView){
42098 if(v !== undefined && v !== null){
42099 var r = this.findRecord(this.valueField || this.displayField, v);
42101 this.select(this.store.indexOf(r), scrollIntoView);
42109 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42110 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42111 * @param {Number} index The zero-based index of the list item to select
42112 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42113 * selected item if it is not currently in view (defaults to true)
42115 select : function(index, scrollIntoView){
42116 this.selectedIndex = index;
42117 this.view.select(index);
42118 if(scrollIntoView !== false){
42119 var el = this.view.getNode(index);
42121 this.innerList.scrollChildIntoView(el, false);
42127 selectNext : function(){
42128 var ct = this.store.getCount();
42130 if(this.selectedIndex == -1){
42132 }else if(this.selectedIndex < ct-1){
42133 this.select(this.selectedIndex+1);
42139 selectPrev : function(){
42140 var ct = this.store.getCount();
42142 if(this.selectedIndex == -1){
42144 }else if(this.selectedIndex != 0){
42145 this.select(this.selectedIndex-1);
42151 onKeyUp : function(e){
42152 if(this.editable !== false && !e.isSpecialKey()){
42153 this.lastKey = e.getKey();
42154 this.dqTask.delay(this.queryDelay);
42159 validateBlur : function(){
42160 return !this.list || !this.list.isVisible();
42164 initQuery : function(){
42165 this.doQuery(this.getRawValue());
42169 doForce : function(){
42170 if(this.el.dom.value.length > 0){
42171 this.el.dom.value =
42172 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42178 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42179 * query allowing the query action to be canceled if needed.
42180 * @param {String} query The SQL query to execute
42181 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42182 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42183 * saved in the current store (defaults to false)
42185 doQuery : function(q, forceAll){
42186 if(q === undefined || q === null){
42191 forceAll: forceAll,
42195 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42199 forceAll = qe.forceAll;
42200 if(forceAll === true || (q.length >= this.minChars)){
42201 if(this.lastQuery != q || this.alwaysQuery){
42202 this.lastQuery = q;
42203 if(this.mode == 'local'){
42204 this.selectedIndex = -1;
42206 this.store.clearFilter();
42208 this.store.filter(this.displayField, q);
42212 this.store.baseParams[this.queryParam] = q;
42214 params: this.getParams(q)
42219 this.selectedIndex = -1;
42226 getParams : function(q){
42228 //p[this.queryParam] = q;
42231 p.limit = this.pageSize;
42237 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42239 collapse : function(){
42240 if(!this.isExpanded()){
42244 Roo.get(document).un('mousedown', this.collapseIf, this);
42245 Roo.get(document).un('mousewheel', this.collapseIf, this);
42246 if (!this.editable) {
42247 Roo.get(document).un('keydown', this.listKeyPress, this);
42249 this.fireEvent('collapse', this);
42253 collapseIf : function(e){
42254 if(!e.within(this.wrap) && !e.within(this.list)){
42260 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42262 expand : function(){
42263 if(this.isExpanded() || !this.hasFocus){
42266 this.list.alignTo(this.el, this.listAlign);
42268 Roo.get(document).on('mousedown', this.collapseIf, this);
42269 Roo.get(document).on('mousewheel', this.collapseIf, this);
42270 if (!this.editable) {
42271 Roo.get(document).on('keydown', this.listKeyPress, this);
42274 this.fireEvent('expand', this);
42278 // Implements the default empty TriggerField.onTriggerClick function
42279 onTriggerClick : function(){
42283 if(this.isExpanded()){
42285 if (!this.blockFocus) {
42290 this.hasFocus = true;
42291 if(this.triggerAction == 'all') {
42292 this.doQuery(this.allQuery, true);
42294 this.doQuery(this.getRawValue());
42296 if (!this.blockFocus) {
42301 listKeyPress : function(e)
42303 //Roo.log('listkeypress');
42304 // scroll to first matching element based on key pres..
42305 if (e.isSpecialKey()) {
42308 var k = String.fromCharCode(e.getKey()).toUpperCase();
42311 var csel = this.view.getSelectedNodes();
42312 var cselitem = false;
42314 var ix = this.view.indexOf(csel[0]);
42315 cselitem = this.store.getAt(ix);
42316 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42322 this.store.each(function(v) {
42324 // start at existing selection.
42325 if (cselitem.id == v.id) {
42331 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42332 match = this.store.indexOf(v);
42337 if (match === false) {
42338 return true; // no more action?
42341 this.view.select(match);
42342 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42343 sn.scrollIntoView(sn.dom.parentNode, false);
42347 * @cfg {Boolean} grow
42351 * @cfg {Number} growMin
42355 * @cfg {Number} growMax
42363 * Copyright(c) 2010-2012, Roo J Solutions Limited
42370 * @class Roo.form.ComboBoxArray
42371 * @extends Roo.form.TextField
42372 * A facebook style adder... for lists of email / people / countries etc...
42373 * pick multiple items from a combo box, and shows each one.
42375 * Fred [x] Brian [x] [Pick another |v]
42378 * For this to work: it needs various extra information
42379 * - normal combo problay has
42381 * + displayField, valueField
42383 * For our purpose...
42386 * If we change from 'extends' to wrapping...
42393 * Create a new ComboBoxArray.
42394 * @param {Object} config Configuration options
42398 Roo.form.ComboBoxArray = function(config)
42402 * @event beforeremove
42403 * Fires before remove the value from the list
42404 * @param {Roo.form.ComboBoxArray} _self This combo box array
42405 * @param {Roo.form.ComboBoxArray.Item} item removed item
42407 'beforeremove' : true,
42410 * Fires when remove the value from the list
42411 * @param {Roo.form.ComboBoxArray} _self This combo box array
42412 * @param {Roo.form.ComboBoxArray.Item} item removed item
42419 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42421 this.items = new Roo.util.MixedCollection(false);
42423 // construct the child combo...
42433 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42436 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42441 // behavies liek a hiddne field
42442 inputType: 'hidden',
42444 * @cfg {Number} width The width of the box that displays the selected element
42451 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42455 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42457 hiddenName : false,
42459 * @cfg {String} seperator The value seperator normally ','
42463 // private the array of items that are displayed..
42465 // private - the hidden field el.
42467 // private - the filed el..
42470 //validateValue : function() { return true; }, // all values are ok!
42471 //onAddClick: function() { },
42473 onRender : function(ct, position)
42476 // create the standard hidden element
42477 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42480 // give fake names to child combo;
42481 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42482 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42484 this.combo = Roo.factory(this.combo, Roo.form);
42485 this.combo.onRender(ct, position);
42486 if (typeof(this.combo.width) != 'undefined') {
42487 this.combo.onResize(this.combo.width,0);
42490 this.combo.initEvents();
42492 // assigned so form know we need to do this..
42493 this.store = this.combo.store;
42494 this.valueField = this.combo.valueField;
42495 this.displayField = this.combo.displayField ;
42498 this.combo.wrap.addClass('x-cbarray-grp');
42500 var cbwrap = this.combo.wrap.createChild(
42501 {tag: 'div', cls: 'x-cbarray-cb'},
42506 this.hiddenEl = this.combo.wrap.createChild({
42507 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42509 this.el = this.combo.wrap.createChild({
42510 tag: 'input', type:'hidden' , name: this.name, value : ''
42512 // this.el.dom.removeAttribute("name");
42515 this.outerWrap = this.combo.wrap;
42516 this.wrap = cbwrap;
42518 this.outerWrap.setWidth(this.width);
42519 this.outerWrap.dom.removeChild(this.el.dom);
42521 this.wrap.dom.appendChild(this.el.dom);
42522 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42523 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42525 this.combo.trigger.setStyle('position','relative');
42526 this.combo.trigger.setStyle('left', '0px');
42527 this.combo.trigger.setStyle('top', '2px');
42529 this.combo.el.setStyle('vertical-align', 'text-bottom');
42531 //this.trigger.setStyle('vertical-align', 'top');
42533 // this should use the code from combo really... on('add' ....)
42537 this.adder = this.outerWrap.createChild(
42538 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42540 this.adder.on('click', function(e) {
42541 _t.fireEvent('adderclick', this, e);
42545 //this.adder.on('click', this.onAddClick, _t);
42548 this.combo.on('select', function(cb, rec, ix) {
42549 this.addItem(rec.data);
42552 cb.el.dom.value = '';
42553 //cb.lastData = rec.data;
42562 getName: function()
42564 // returns hidden if it's set..
42565 if (!this.rendered) {return ''};
42566 return this.hiddenName ? this.hiddenName : this.name;
42571 onResize: function(w, h){
42574 // not sure if this is needed..
42575 //this.combo.onResize(w,h);
42577 if(typeof w != 'number'){
42578 // we do not handle it!?!?
42581 var tw = this.combo.trigger.getWidth();
42582 tw += this.addicon ? this.addicon.getWidth() : 0;
42583 tw += this.editicon ? this.editicon.getWidth() : 0;
42585 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42587 this.combo.trigger.setStyle('left', '0px');
42589 if(this.list && this.listWidth === undefined){
42590 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42591 this.list.setWidth(lw);
42592 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42599 addItem: function(rec)
42601 var valueField = this.combo.valueField;
42602 var displayField = this.combo.displayField;
42604 if (this.items.indexOfKey(rec[valueField]) > -1) {
42605 //console.log("GOT " + rec.data.id);
42609 var x = new Roo.form.ComboBoxArray.Item({
42610 //id : rec[this.idField],
42612 displayField : displayField ,
42613 tipField : displayField ,
42617 this.items.add(rec[valueField],x);
42618 // add it before the element..
42619 this.updateHiddenEl();
42620 x.render(this.outerWrap, this.wrap.dom);
42621 // add the image handler..
42624 updateHiddenEl : function()
42627 if (!this.hiddenEl) {
42631 var idField = this.combo.valueField;
42633 this.items.each(function(f) {
42634 ar.push(f.data[idField]);
42636 this.hiddenEl.dom.value = ar.join(this.seperator);
42642 this.items.clear();
42644 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42648 this.el.dom.value = '';
42649 if (this.hiddenEl) {
42650 this.hiddenEl.dom.value = '';
42654 getValue: function()
42656 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42658 setValue: function(v) // not a valid action - must use addItems..
42663 if (this.store.isLocal && (typeof(v) == 'string')) {
42664 // then we can use the store to find the values..
42665 // comma seperated at present.. this needs to allow JSON based encoding..
42666 this.hiddenEl.value = v;
42668 Roo.each(v.split(this.seperator), function(k) {
42669 Roo.log("CHECK " + this.valueField + ',' + k);
42670 var li = this.store.query(this.valueField, k);
42675 add[this.valueField] = k;
42676 add[this.displayField] = li.item(0).data[this.displayField];
42682 if (typeof(v) == 'object' ) {
42683 // then let's assume it's an array of objects..
42684 Roo.each(v, function(l) {
42686 if (typeof(l) == 'string') {
42688 add[this.valueField] = l;
42689 add[this.displayField] = l
42698 setFromData: function(v)
42700 // this recieves an object, if setValues is called.
42702 this.el.dom.value = v[this.displayField];
42703 this.hiddenEl.dom.value = v[this.valueField];
42704 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42707 var kv = v[this.valueField];
42708 var dv = v[this.displayField];
42709 kv = typeof(kv) != 'string' ? '' : kv;
42710 dv = typeof(dv) != 'string' ? '' : dv;
42713 var keys = kv.split(this.seperator);
42714 var display = dv.split(this.seperator);
42715 for (var i = 0 ; i < keys.length; i++) {
42717 add[this.valueField] = keys[i];
42718 add[this.displayField] = display[i];
42726 * Validates the combox array value
42727 * @return {Boolean} True if the value is valid, else false
42729 validate : function(){
42730 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42731 this.clearInvalid();
42737 validateValue : function(value){
42738 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42746 isDirty : function() {
42747 if(this.disabled) {
42752 var d = Roo.decode(String(this.originalValue));
42754 return String(this.getValue()) !== String(this.originalValue);
42757 var originalValue = [];
42759 for (var i = 0; i < d.length; i++){
42760 originalValue.push(d[i][this.valueField]);
42763 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42772 * @class Roo.form.ComboBoxArray.Item
42773 * @extends Roo.BoxComponent
42774 * A selected item in the list
42775 * Fred [x] Brian [x] [Pick another |v]
42778 * Create a new item.
42779 * @param {Object} config Configuration options
42782 Roo.form.ComboBoxArray.Item = function(config) {
42783 config.id = Roo.id();
42784 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42787 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42790 displayField : false,
42794 defaultAutoCreate : {
42796 cls: 'x-cbarray-item',
42803 src : Roo.BLANK_IMAGE_URL ,
42811 onRender : function(ct, position)
42813 Roo.form.Field.superclass.onRender.call(this, ct, position);
42816 var cfg = this.getAutoCreate();
42817 this.el = ct.createChild(cfg, position);
42820 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42822 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42823 this.cb.renderer(this.data) :
42824 String.format('{0}',this.data[this.displayField]);
42827 this.el.child('div').dom.setAttribute('qtip',
42828 String.format('{0}',this.data[this.tipField])
42831 this.el.child('img').on('click', this.remove, this);
42835 remove : function()
42837 if(this.cb.disabled){
42841 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42842 this.cb.items.remove(this);
42843 this.el.child('img').un('click', this.remove, this);
42845 this.cb.updateHiddenEl();
42847 this.cb.fireEvent('remove', this.cb, this);
42852 * RooJS Library 1.1.1
42853 * Copyright(c) 2008-2011 Alan Knowles
42860 * @class Roo.form.ComboNested
42861 * @extends Roo.form.ComboBox
42862 * A combobox for that allows selection of nested items in a list,
42877 * Create a new ComboNested
42878 * @param {Object} config Configuration options
42880 Roo.form.ComboNested = function(config){
42881 Roo.form.ComboCheck.superclass.constructor.call(this, config);
42882 // should verify some data...
42884 // hiddenName = required..
42885 // displayField = required
42886 // valudField == required
42887 var req= [ 'hiddenName', 'displayField', 'valueField' ];
42889 Roo.each(req, function(e) {
42890 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
42891 throw "Roo.form.ComboNested : missing value for: " + e;
42898 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
42901 * @config {Number} max Number of columns to show
42906 list : null, // the outermost div..
42907 innerLists : null, // the
42911 loadingChildren : false,
42913 onRender : function(ct, position)
42915 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
42917 if(this.hiddenName){
42918 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42920 this.hiddenField.value =
42921 this.hiddenValue !== undefined ? this.hiddenValue :
42922 this.value !== undefined ? this.value : '';
42924 // prevent input submission
42925 this.el.dom.removeAttribute('name');
42931 this.el.dom.setAttribute('autocomplete', 'off');
42934 var cls = 'x-combo-list';
42936 this.list = new Roo.Layer({
42937 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
42940 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
42941 this.list.setWidth(lw);
42942 this.list.swallowEvent('mousewheel');
42943 this.assetHeight = 0;
42946 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
42947 this.assetHeight += this.header.getHeight();
42949 this.innerLists = [];
42952 for (var i =0 ; i < this.maxColumns; i++) {
42953 this.onRenderList( cls, i);
42956 // always needs footer, as we are going to have an 'OK' button.
42957 this.footer = this.list.createChild({cls:cls+'-ft'});
42958 this.pageTb = new Roo.Toolbar(this.footer);
42963 handler: function()
42969 if ( this.allowBlank && !this.disableClear) {
42971 this.pageTb.add(new Roo.Toolbar.Fill(), {
42972 cls: 'x-btn-icon x-btn-clear',
42974 handler: function()
42977 _this.clearValue();
42978 _this.onSelect(false, -1);
42983 this.assetHeight += this.footer.getHeight();
42987 onRenderList : function ( cls, i)
42990 var lw = Math.floor(
42991 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
42994 this.list.setWidth(lw); // default to '1'
42996 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
42997 //il.on('mouseover', this.onViewOver, this, { list: i });
42998 //il.on('mousemove', this.onViewMove, this, { list: i });
43000 il.setStyle({ 'overflow-x' : 'hidden'});
43003 this.tpl = new Roo.Template({
43004 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
43005 isEmpty: function (value, allValues) {
43007 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
43008 return dl ? 'has-children' : 'no-children'
43013 var store = this.store;
43015 store = new Roo.data.SimpleStore({
43016 //fields : this.store.reader.meta.fields,
43017 reader : this.store.reader,
43021 this.stores[i] = store;
43023 var view = this.views[i] = new Roo.View(
43029 selectedClass: this.selectedClass
43032 view.getEl().setWidth(lw);
43033 view.getEl().setStyle({
43034 position: i < 1 ? 'relative' : 'absolute',
43036 left: (i * lw ) + 'px',
43037 display : i > 0 ? 'none' : 'block'
43039 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
43040 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
43041 //view.on('click', this.onViewClick, this, { list : i });
43043 store.on('beforeload', this.onBeforeLoad, this);
43044 store.on('load', this.onLoad, this, { list : i});
43045 store.on('loadexception', this.onLoadException, this);
43047 // hide the other vies..
43053 restrictHeight : function()
43056 Roo.each(this.innerLists, function(il,i) {
43057 var el = this.views[i].getEl();
43058 el.dom.style.height = '';
43059 var inner = el.dom;
43060 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
43061 // only adjust heights on other ones..
43062 mh = Math.max(h, mh);
43065 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43066 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43073 this.list.beginUpdate();
43074 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43075 this.list.alignTo(this.el, this.listAlign);
43076 this.list.endUpdate();
43081 // -- store handlers..
43083 onBeforeLoad : function()
43085 if(!this.hasFocus){
43088 this.innerLists[0].update(this.loadingText ?
43089 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43090 this.restrictHeight();
43091 this.selectedIndex = -1;
43094 onLoad : function(a,b,c,d)
43096 if (!this.loadingChildren) {
43097 // then we are loading the top level. - hide the children
43098 for (var i = 1;i < this.views.length; i++) {
43099 this.views[i].getEl().setStyle({ display : 'none' });
43101 var lw = Math.floor(
43102 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43105 this.list.setWidth(lw); // default to '1'
43109 if(!this.hasFocus){
43113 if(this.store.getCount() > 0) {
43115 this.restrictHeight();
43117 this.onEmptyResults();
43120 if (!this.loadingChildren) {
43121 this.selectActive();
43124 this.stores[1].loadData([]);
43125 this.stores[2].loadData([]);
43134 onLoadException : function()
43137 Roo.log(this.store.reader.jsonData);
43138 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43139 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43144 // no cleaning of leading spaces on blur here.
43145 cleanLeadingSpace : function(e) { },
43148 onSelectChange : function (view, sels, opts )
43150 var ix = view.getSelectedIndexes();
43152 if (opts.list > this.maxColumns - 2) {
43153 if (view.store.getCount()< 1) {
43154 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43158 // used to clear ?? but if we are loading unselected
43159 this.setFromData(view.store.getAt(ix[0]).data);
43168 // this get's fired when trigger opens..
43169 // this.setFromData({});
43170 var str = this.stores[opts.list+1];
43171 str.data.clear(); // removeall wihtout the fire events..
43175 var rec = view.store.getAt(ix[0]);
43177 this.setFromData(rec.data);
43178 this.fireEvent('select', this, rec, ix[0]);
43180 var lw = Math.floor(
43182 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43183 ) / this.maxColumns
43185 this.loadingChildren = true;
43186 this.stores[opts.list+1].loadDataFromChildren( rec );
43187 this.loadingChildren = false;
43188 var dl = this.stores[opts.list+1]. getTotalCount();
43190 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43192 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43193 for (var i = opts.list+2; i < this.views.length;i++) {
43194 this.views[i].getEl().setStyle({ display : 'none' });
43197 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43198 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43200 if (this.isLoading) {
43201 // this.selectActive(opts.list);
43209 onDoubleClick : function()
43211 this.collapse(); //??
43219 recordToStack : function(store, prop, value, stack)
43221 var cstore = new Roo.data.SimpleStore({
43222 //fields : this.store.reader.meta.fields, // we need array reader.. for
43223 reader : this.store.reader,
43227 var record = false;
43229 if(store.getCount() < 1){
43232 store.each(function(r){
43233 if(r.data[prop] == value){
43238 if (r.data.cn && r.data.cn.length) {
43239 cstore.loadDataFromChildren( r);
43240 var cret = _this.recordToStack(cstore, prop, value, stack);
43241 if (cret !== false) {
43250 if (record == false) {
43253 stack.unshift(srec);
43258 * find the stack of stores that match our value.
43263 selectActive : function ()
43265 // if store is not loaded, then we will need to wait for that to happen first.
43267 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43268 for (var i = 0; i < stack.length; i++ ) {
43269 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43281 * Ext JS Library 1.1.1
43282 * Copyright(c) 2006-2007, Ext JS, LLC.
43284 * Originally Released Under LGPL - original licence link has changed is not relivant.
43287 * <script type="text/javascript">
43290 * @class Roo.form.Checkbox
43291 * @extends Roo.form.Field
43292 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43294 * Creates a new Checkbox
43295 * @param {Object} config Configuration options
43297 Roo.form.Checkbox = function(config){
43298 Roo.form.Checkbox.superclass.constructor.call(this, config);
43302 * Fires when the checkbox is checked or unchecked.
43303 * @param {Roo.form.Checkbox} this This checkbox
43304 * @param {Boolean} checked The new checked value
43310 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43312 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43314 focusClass : undefined,
43316 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43318 fieldClass: "x-form-field",
43320 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43324 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43325 * {tag: "input", type: "checkbox", autocomplete: "off"})
43327 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43329 * @cfg {String} boxLabel The text that appears beside the checkbox
43333 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43337 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43339 valueOff: '0', // value when not checked..
43341 actionMode : 'viewEl',
43344 itemCls : 'x-menu-check-item x-form-item',
43345 groupClass : 'x-menu-group-item',
43346 inputType : 'hidden',
43349 inSetChecked: false, // check that we are not calling self...
43351 inputElement: false, // real input element?
43352 basedOn: false, // ????
43354 isFormField: true, // not sure where this is needed!!!!
43356 onResize : function(){
43357 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43358 if(!this.boxLabel){
43359 this.el.alignTo(this.wrap, 'c-c');
43363 initEvents : function(){
43364 Roo.form.Checkbox.superclass.initEvents.call(this);
43365 this.el.on("click", this.onClick, this);
43366 this.el.on("change", this.onClick, this);
43370 getResizeEl : function(){
43374 getPositionEl : function(){
43379 onRender : function(ct, position){
43380 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43382 if(this.inputValue !== undefined){
43383 this.el.dom.value = this.inputValue;
43386 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43387 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43388 var viewEl = this.wrap.createChild({
43389 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43390 this.viewEl = viewEl;
43391 this.wrap.on('click', this.onClick, this);
43393 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43394 this.el.on('propertychange', this.setFromHidden, this); //ie
43399 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43400 // viewEl.on('click', this.onClick, this);
43402 //if(this.checked){
43403 this.setChecked(this.checked);
43405 //this.checked = this.el.dom;
43411 initValue : Roo.emptyFn,
43414 * Returns the checked state of the checkbox.
43415 * @return {Boolean} True if checked, else false
43417 getValue : function(){
43419 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43421 return this.valueOff;
43426 onClick : function(){
43427 if (this.disabled) {
43430 this.setChecked(!this.checked);
43432 //if(this.el.dom.checked != this.checked){
43433 // this.setValue(this.el.dom.checked);
43438 * Sets the checked state of the checkbox.
43439 * On is always based on a string comparison between inputValue and the param.
43440 * @param {Boolean/String} value - the value to set
43441 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43443 setValue : function(v,suppressEvent){
43446 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43447 //if(this.el && this.el.dom){
43448 // this.el.dom.checked = this.checked;
43449 // this.el.dom.defaultChecked = this.checked;
43451 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43452 //this.fireEvent("check", this, this.checked);
43455 setChecked : function(state,suppressEvent)
43457 if (this.inSetChecked) {
43458 this.checked = state;
43464 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43466 this.checked = state;
43467 if(suppressEvent !== true){
43468 this.fireEvent('check', this, state);
43470 this.inSetChecked = true;
43471 this.el.dom.value = state ? this.inputValue : this.valueOff;
43472 this.inSetChecked = false;
43475 // handle setting of hidden value by some other method!!?!?
43476 setFromHidden: function()
43481 //console.log("SET FROM HIDDEN");
43482 //alert('setFrom hidden');
43483 this.setValue(this.el.dom.value);
43486 onDestroy : function()
43489 Roo.get(this.viewEl).remove();
43492 Roo.form.Checkbox.superclass.onDestroy.call(this);
43495 setBoxLabel : function(str)
43497 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43502 * Ext JS Library 1.1.1
43503 * Copyright(c) 2006-2007, Ext JS, LLC.
43505 * Originally Released Under LGPL - original licence link has changed is not relivant.
43508 * <script type="text/javascript">
43512 * @class Roo.form.Radio
43513 * @extends Roo.form.Checkbox
43514 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43515 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43517 * Creates a new Radio
43518 * @param {Object} config Configuration options
43520 Roo.form.Radio = function(){
43521 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43523 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43524 inputType: 'radio',
43527 * If this radio is part of a group, it will return the selected value
43530 getGroupValue : function(){
43531 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43535 onRender : function(ct, position){
43536 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43538 if(this.inputValue !== undefined){
43539 this.el.dom.value = this.inputValue;
43542 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43543 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43544 //var viewEl = this.wrap.createChild({
43545 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43546 //this.viewEl = viewEl;
43547 //this.wrap.on('click', this.onClick, this);
43549 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43550 //this.el.on('propertychange', this.setFromHidden, this); //ie
43555 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43556 // viewEl.on('click', this.onClick, this);
43559 this.el.dom.checked = 'checked' ;
43565 });//<script type="text/javascript">
43568 * Based Ext JS Library 1.1.1
43569 * Copyright(c) 2006-2007, Ext JS, LLC.
43575 * @class Roo.HtmlEditorCore
43576 * @extends Roo.Component
43577 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43579 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43582 Roo.HtmlEditorCore = function(config){
43585 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43590 * @event initialize
43591 * Fires when the editor is fully initialized (including the iframe)
43592 * @param {Roo.HtmlEditorCore} this
43597 * Fires when the editor is first receives the focus. Any insertion must wait
43598 * until after this event.
43599 * @param {Roo.HtmlEditorCore} this
43603 * @event beforesync
43604 * Fires before the textarea is updated with content from the editor iframe. Return false
43605 * to cancel the sync.
43606 * @param {Roo.HtmlEditorCore} this
43607 * @param {String} html
43611 * @event beforepush
43612 * Fires before the iframe editor is updated with content from the textarea. Return false
43613 * to cancel the push.
43614 * @param {Roo.HtmlEditorCore} this
43615 * @param {String} html
43620 * Fires when the textarea is updated with content from the editor iframe.
43621 * @param {Roo.HtmlEditorCore} this
43622 * @param {String} html
43627 * Fires when the iframe editor is updated with content from the textarea.
43628 * @param {Roo.HtmlEditorCore} this
43629 * @param {String} html
43634 * @event editorevent
43635 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43636 * @param {Roo.HtmlEditorCore} this
43642 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43644 // defaults : white / black...
43645 this.applyBlacklists();
43652 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43656 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43662 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43667 * @cfg {Number} height (in pixels)
43671 * @cfg {Number} width (in pixels)
43676 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43679 stylesheets: false,
43684 // private properties
43685 validationEvent : false,
43687 initialized : false,
43689 sourceEditMode : false,
43690 onFocus : Roo.emptyFn,
43692 hideMode:'offsets',
43696 // blacklist + whitelisted elements..
43703 * Protected method that will not generally be called directly. It
43704 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43705 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43707 getDocMarkup : function(){
43711 // inherit styels from page...??
43712 if (this.stylesheets === false) {
43714 Roo.get(document.head).select('style').each(function(node) {
43715 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43718 Roo.get(document.head).select('link').each(function(node) {
43719 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43722 } else if (!this.stylesheets.length) {
43724 st = '<style type="text/css">' +
43725 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43728 for (var i in this.stylesheets) {
43729 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43734 st += '<style type="text/css">' +
43735 'IMG { cursor: pointer } ' +
43738 var cls = 'roo-htmleditor-body';
43740 if(this.bodyCls.length){
43741 cls += ' ' + this.bodyCls;
43744 return '<html><head>' + st +
43745 //<style type="text/css">' +
43746 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43748 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43752 onRender : function(ct, position)
43755 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43756 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43759 this.el.dom.style.border = '0 none';
43760 this.el.dom.setAttribute('tabIndex', -1);
43761 this.el.addClass('x-hidden hide');
43765 if(Roo.isIE){ // fix IE 1px bogus margin
43766 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43770 this.frameId = Roo.id();
43774 var iframe = this.owner.wrap.createChild({
43776 cls: 'form-control', // bootstrap..
43778 name: this.frameId,
43779 frameBorder : 'no',
43780 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43785 this.iframe = iframe.dom;
43787 this.assignDocWin();
43789 this.doc.designMode = 'on';
43792 this.doc.write(this.getDocMarkup());
43796 var task = { // must defer to wait for browser to be ready
43798 //console.log("run task?" + this.doc.readyState);
43799 this.assignDocWin();
43800 if(this.doc.body || this.doc.readyState == 'complete'){
43802 this.doc.designMode="on";
43806 Roo.TaskMgr.stop(task);
43807 this.initEditor.defer(10, this);
43814 Roo.TaskMgr.start(task);
43819 onResize : function(w, h)
43821 Roo.log('resize: ' +w + ',' + h );
43822 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43826 if(typeof w == 'number'){
43828 this.iframe.style.width = w + 'px';
43830 if(typeof h == 'number'){
43832 this.iframe.style.height = h + 'px';
43834 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43841 * Toggles the editor between standard and source edit mode.
43842 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43844 toggleSourceEdit : function(sourceEditMode){
43846 this.sourceEditMode = sourceEditMode === true;
43848 if(this.sourceEditMode){
43850 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43853 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43854 //this.iframe.className = '';
43857 //this.setSize(this.owner.wrap.getSize());
43858 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43865 * Protected method that will not generally be called directly. If you need/want
43866 * custom HTML cleanup, this is the method you should override.
43867 * @param {String} html The HTML to be cleaned
43868 * return {String} The cleaned HTML
43870 cleanHtml : function(html){
43871 html = String(html);
43872 if(html.length > 5){
43873 if(Roo.isSafari){ // strip safari nonsense
43874 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43877 if(html == ' '){
43884 * HTML Editor -> Textarea
43885 * Protected method that will not generally be called directly. Syncs the contents
43886 * of the editor iframe with the textarea.
43888 syncValue : function(){
43889 if(this.initialized){
43890 var bd = (this.doc.body || this.doc.documentElement);
43891 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43892 var html = bd.innerHTML;
43894 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43895 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43897 html = '<div style="'+m[0]+'">' + html + '</div>';
43900 html = this.cleanHtml(html);
43901 // fix up the special chars.. normaly like back quotes in word...
43902 // however we do not want to do this with chinese..
43903 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
43905 var cc = match.charCodeAt();
43907 // Get the character value, handling surrogate pairs
43908 if (match.length == 2) {
43909 // It's a surrogate pair, calculate the Unicode code point
43910 var high = match.charCodeAt(0) - 0xD800;
43911 var low = match.charCodeAt(1) - 0xDC00;
43912 cc = (high * 0x400) + low + 0x10000;
43914 (cc >= 0x4E00 && cc < 0xA000 ) ||
43915 (cc >= 0x3400 && cc < 0x4E00 ) ||
43916 (cc >= 0xf900 && cc < 0xfb00 )
43921 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
43922 return "&#" + cc + ";";
43929 if(this.owner.fireEvent('beforesync', this, html) !== false){
43930 this.el.dom.value = html;
43931 this.owner.fireEvent('sync', this, html);
43937 * Protected method that will not generally be called directly. Pushes the value of the textarea
43938 * into the iframe editor.
43940 pushValue : function(){
43941 if(this.initialized){
43942 var v = this.el.dom.value.trim();
43944 // if(v.length < 1){
43948 if(this.owner.fireEvent('beforepush', this, v) !== false){
43949 var d = (this.doc.body || this.doc.documentElement);
43951 this.cleanUpPaste();
43952 this.el.dom.value = d.innerHTML;
43953 this.owner.fireEvent('push', this, v);
43959 deferFocus : function(){
43960 this.focus.defer(10, this);
43964 focus : function(){
43965 if(this.win && !this.sourceEditMode){
43972 assignDocWin: function()
43974 var iframe = this.iframe;
43977 this.doc = iframe.contentWindow.document;
43978 this.win = iframe.contentWindow;
43980 // if (!Roo.get(this.frameId)) {
43983 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43984 // this.win = Roo.get(this.frameId).dom.contentWindow;
43986 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43990 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43991 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43996 initEditor : function(){
43997 //console.log("INIT EDITOR");
43998 this.assignDocWin();
44002 this.doc.designMode="on";
44004 this.doc.write(this.getDocMarkup());
44007 var dbody = (this.doc.body || this.doc.documentElement);
44008 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
44009 // this copies styles from the containing element into thsi one..
44010 // not sure why we need all of this..
44011 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
44013 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
44014 //ss['background-attachment'] = 'fixed'; // w3c
44015 dbody.bgProperties = 'fixed'; // ie
44016 //Roo.DomHelper.applyStyles(dbody, ss);
44017 Roo.EventManager.on(this.doc, {
44018 //'mousedown': this.onEditorEvent,
44019 'mouseup': this.onEditorEvent,
44020 'dblclick': this.onEditorEvent,
44021 'click': this.onEditorEvent,
44022 'keyup': this.onEditorEvent,
44027 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
44029 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
44030 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
44032 this.initialized = true;
44034 this.owner.fireEvent('initialize', this);
44039 onDestroy : function(){
44045 //for (var i =0; i < this.toolbars.length;i++) {
44046 // // fixme - ask toolbars for heights?
44047 // this.toolbars[i].onDestroy();
44050 //this.wrap.dom.innerHTML = '';
44051 //this.wrap.remove();
44056 onFirstFocus : function(){
44058 this.assignDocWin();
44061 this.activated = true;
44064 if(Roo.isGecko){ // prevent silly gecko errors
44066 var s = this.win.getSelection();
44067 if(!s.focusNode || s.focusNode.nodeType != 3){
44068 var r = s.getRangeAt(0);
44069 r.selectNodeContents((this.doc.body || this.doc.documentElement));
44074 this.execCmd('useCSS', true);
44075 this.execCmd('styleWithCSS', false);
44078 this.owner.fireEvent('activate', this);
44082 adjustFont: function(btn){
44083 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44084 //if(Roo.isSafari){ // safari
44087 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44088 if(Roo.isSafari){ // safari
44089 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44090 v = (v < 10) ? 10 : v;
44091 v = (v > 48) ? 48 : v;
44092 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44097 v = Math.max(1, v+adjust);
44099 this.execCmd('FontSize', v );
44102 onEditorEvent : function(e)
44104 this.owner.fireEvent('editorevent', this, e);
44105 // this.updateToolbar();
44106 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44109 insertTag : function(tg)
44111 // could be a bit smarter... -> wrap the current selected tRoo..
44112 if (tg.toLowerCase() == 'span' ||
44113 tg.toLowerCase() == 'code' ||
44114 tg.toLowerCase() == 'sup' ||
44115 tg.toLowerCase() == 'sub'
44118 range = this.createRange(this.getSelection());
44119 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44120 wrappingNode.appendChild(range.extractContents());
44121 range.insertNode(wrappingNode);
44128 this.execCmd("formatblock", tg);
44132 insertText : function(txt)
44136 var range = this.createRange();
44137 range.deleteContents();
44138 //alert(Sender.getAttribute('label'));
44140 range.insertNode(this.doc.createTextNode(txt));
44146 * Executes a Midas editor command on the editor document and performs necessary focus and
44147 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44148 * @param {String} cmd The Midas command
44149 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44151 relayCmd : function(cmd, value){
44153 this.execCmd(cmd, value);
44154 this.owner.fireEvent('editorevent', this);
44155 //this.updateToolbar();
44156 this.owner.deferFocus();
44160 * Executes a Midas editor command directly on the editor document.
44161 * For visual commands, you should use {@link #relayCmd} instead.
44162 * <b>This should only be called after the editor is initialized.</b>
44163 * @param {String} cmd The Midas command
44164 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44166 execCmd : function(cmd, value){
44167 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44174 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44176 * @param {String} text | dom node..
44178 insertAtCursor : function(text)
44181 if(!this.activated){
44187 var r = this.doc.selection.createRange();
44198 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44202 // from jquery ui (MIT licenced)
44204 var win = this.win;
44206 if (win.getSelection && win.getSelection().getRangeAt) {
44207 range = win.getSelection().getRangeAt(0);
44208 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44209 range.insertNode(node);
44210 } else if (win.document.selection && win.document.selection.createRange) {
44211 // no firefox support
44212 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44213 win.document.selection.createRange().pasteHTML(txt);
44215 // no firefox support
44216 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44217 this.execCmd('InsertHTML', txt);
44226 mozKeyPress : function(e){
44228 var c = e.getCharCode(), cmd;
44231 c = String.fromCharCode(c).toLowerCase();
44245 this.cleanUpPaste.defer(100, this);
44253 e.preventDefault();
44261 fixKeys : function(){ // load time branching for fastest keydown performance
44263 return function(e){
44264 var k = e.getKey(), r;
44267 r = this.doc.selection.createRange();
44270 r.pasteHTML('    ');
44277 r = this.doc.selection.createRange();
44279 var target = r.parentElement();
44280 if(!target || target.tagName.toLowerCase() != 'li'){
44282 r.pasteHTML('<br />');
44288 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44289 this.cleanUpPaste.defer(100, this);
44295 }else if(Roo.isOpera){
44296 return function(e){
44297 var k = e.getKey();
44301 this.execCmd('InsertHTML','    ');
44304 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44305 this.cleanUpPaste.defer(100, this);
44310 }else if(Roo.isSafari){
44311 return function(e){
44312 var k = e.getKey();
44316 this.execCmd('InsertText','\t');
44320 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44321 this.cleanUpPaste.defer(100, this);
44329 getAllAncestors: function()
44331 var p = this.getSelectedNode();
44334 a.push(p); // push blank onto stack..
44335 p = this.getParentElement();
44339 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44343 a.push(this.doc.body);
44347 lastSelNode : false,
44350 getSelection : function()
44352 this.assignDocWin();
44353 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44356 getSelectedNode: function()
44358 // this may only work on Gecko!!!
44360 // should we cache this!!!!
44365 var range = this.createRange(this.getSelection()).cloneRange();
44368 var parent = range.parentElement();
44370 var testRange = range.duplicate();
44371 testRange.moveToElementText(parent);
44372 if (testRange.inRange(range)) {
44375 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44378 parent = parent.parentElement;
44383 // is ancestor a text element.
44384 var ac = range.commonAncestorContainer;
44385 if (ac.nodeType == 3) {
44386 ac = ac.parentNode;
44389 var ar = ac.childNodes;
44392 var other_nodes = [];
44393 var has_other_nodes = false;
44394 for (var i=0;i<ar.length;i++) {
44395 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44398 // fullly contained node.
44400 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44405 // probably selected..
44406 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44407 other_nodes.push(ar[i]);
44411 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44416 has_other_nodes = true;
44418 if (!nodes.length && other_nodes.length) {
44419 nodes= other_nodes;
44421 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44427 createRange: function(sel)
44429 // this has strange effects when using with
44430 // top toolbar - not sure if it's a great idea.
44431 //this.editor.contentWindow.focus();
44432 if (typeof sel != "undefined") {
44434 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44436 return this.doc.createRange();
44439 return this.doc.createRange();
44442 getParentElement: function()
44445 this.assignDocWin();
44446 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44448 var range = this.createRange(sel);
44451 var p = range.commonAncestorContainer;
44452 while (p.nodeType == 3) { // text node
44463 * Range intersection.. the hard stuff...
44467 * [ -- selected range --- ]
44471 * if end is before start or hits it. fail.
44472 * if start is after end or hits it fail.
44474 * if either hits (but other is outside. - then it's not
44480 // @see http://www.thismuchiknow.co.uk/?p=64.
44481 rangeIntersectsNode : function(range, node)
44483 var nodeRange = node.ownerDocument.createRange();
44485 nodeRange.selectNode(node);
44487 nodeRange.selectNodeContents(node);
44490 var rangeStartRange = range.cloneRange();
44491 rangeStartRange.collapse(true);
44493 var rangeEndRange = range.cloneRange();
44494 rangeEndRange.collapse(false);
44496 var nodeStartRange = nodeRange.cloneRange();
44497 nodeStartRange.collapse(true);
44499 var nodeEndRange = nodeRange.cloneRange();
44500 nodeEndRange.collapse(false);
44502 return rangeStartRange.compareBoundaryPoints(
44503 Range.START_TO_START, nodeEndRange) == -1 &&
44504 rangeEndRange.compareBoundaryPoints(
44505 Range.START_TO_START, nodeStartRange) == 1;
44509 rangeCompareNode : function(range, node)
44511 var nodeRange = node.ownerDocument.createRange();
44513 nodeRange.selectNode(node);
44515 nodeRange.selectNodeContents(node);
44519 range.collapse(true);
44521 nodeRange.collapse(true);
44523 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44524 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44526 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44528 var nodeIsBefore = ss == 1;
44529 var nodeIsAfter = ee == -1;
44531 if (nodeIsBefore && nodeIsAfter) {
44534 if (!nodeIsBefore && nodeIsAfter) {
44535 return 1; //right trailed.
44538 if (nodeIsBefore && !nodeIsAfter) {
44539 return 2; // left trailed.
44545 // private? - in a new class?
44546 cleanUpPaste : function()
44548 // cleans up the whole document..
44549 Roo.log('cleanuppaste');
44551 this.cleanUpChildren(this.doc.body);
44552 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44553 if (clean != this.doc.body.innerHTML) {
44554 this.doc.body.innerHTML = clean;
44559 cleanWordChars : function(input) {// change the chars to hex code
44560 var he = Roo.HtmlEditorCore;
44562 var output = input;
44563 Roo.each(he.swapCodes, function(sw) {
44564 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44566 output = output.replace(swapper, sw[1]);
44573 cleanUpChildren : function (n)
44575 if (!n.childNodes.length) {
44578 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44579 this.cleanUpChild(n.childNodes[i]);
44586 cleanUpChild : function (node)
44589 //console.log(node);
44590 if (node.nodeName == "#text") {
44591 // clean up silly Windows -- stuff?
44594 if (node.nodeName == "#comment") {
44595 node.parentNode.removeChild(node);
44596 // clean up silly Windows -- stuff?
44599 var lcname = node.tagName.toLowerCase();
44600 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44601 // whitelist of tags..
44603 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44605 node.parentNode.removeChild(node);
44610 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44612 // spans with no attributes - just remove them..
44613 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44614 remove_keep_children = true;
44617 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44618 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44620 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44621 // remove_keep_children = true;
44624 if (remove_keep_children) {
44625 this.cleanUpChildren(node);
44626 // inserts everything just before this node...
44627 while (node.childNodes.length) {
44628 var cn = node.childNodes[0];
44629 node.removeChild(cn);
44630 node.parentNode.insertBefore(cn, node);
44632 node.parentNode.removeChild(node);
44636 if (!node.attributes || !node.attributes.length) {
44641 this.cleanUpChildren(node);
44645 function cleanAttr(n,v)
44648 if (v.match(/^\./) || v.match(/^\//)) {
44651 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44654 if (v.match(/^#/)) {
44657 if (v.match(/^\{/)) { // allow template editing.
44660 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44661 node.removeAttribute(n);
44665 var cwhite = this.cwhite;
44666 var cblack = this.cblack;
44668 function cleanStyle(n,v)
44670 if (v.match(/expression/)) { //XSS?? should we even bother..
44671 node.removeAttribute(n);
44675 var parts = v.split(/;/);
44678 Roo.each(parts, function(p) {
44679 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44683 var l = p.split(':').shift().replace(/\s+/g,'');
44684 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44686 if ( cwhite.length && cblack.indexOf(l) > -1) {
44687 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44688 //node.removeAttribute(n);
44692 // only allow 'c whitelisted system attributes'
44693 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44694 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44695 //node.removeAttribute(n);
44705 if (clean.length) {
44706 node.setAttribute(n, clean.join(';'));
44708 node.removeAttribute(n);
44714 for (var i = node.attributes.length-1; i > -1 ; i--) {
44715 var a = node.attributes[i];
44718 if (a.name.toLowerCase().substr(0,2)=='on') {
44719 node.removeAttribute(a.name);
44722 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44723 node.removeAttribute(a.name);
44726 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44727 cleanAttr(a.name,a.value); // fixme..
44730 if (a.name == 'style') {
44731 cleanStyle(a.name,a.value);
44734 /// clean up MS crap..
44735 // tecnically this should be a list of valid class'es..
44738 if (a.name == 'class') {
44739 if (a.value.match(/^Mso/)) {
44740 node.removeAttribute('class');
44743 if (a.value.match(/^body$/)) {
44744 node.removeAttribute('class');
44755 this.cleanUpChildren(node);
44761 * Clean up MS wordisms...
44763 cleanWord : function(node)
44766 this.cleanWord(this.doc.body);
44771 node.nodeName == 'SPAN' &&
44772 !node.hasAttributes() &&
44773 node.childNodes.length == 1 &&
44774 node.firstChild.nodeName == "#text"
44776 var textNode = node.firstChild;
44777 node.removeChild(textNode);
44778 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44779 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44781 node.parentNode.insertBefore(textNode, node);
44782 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44783 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44785 node.parentNode.removeChild(node);
44788 if (node.nodeName == "#text") {
44789 // clean up silly Windows -- stuff?
44792 if (node.nodeName == "#comment") {
44793 node.parentNode.removeChild(node);
44794 // clean up silly Windows -- stuff?
44798 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44799 node.parentNode.removeChild(node);
44802 //Roo.log(node.tagName);
44803 // remove - but keep children..
44804 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44805 //Roo.log('-- removed');
44806 while (node.childNodes.length) {
44807 var cn = node.childNodes[0];
44808 node.removeChild(cn);
44809 node.parentNode.insertBefore(cn, node);
44810 // move node to parent - and clean it..
44811 this.cleanWord(cn);
44813 node.parentNode.removeChild(node);
44814 /// no need to iterate chidlren = it's got none..
44815 //this.iterateChildren(node, this.cleanWord);
44819 if (node.className.length) {
44821 var cn = node.className.split(/\W+/);
44823 Roo.each(cn, function(cls) {
44824 if (cls.match(/Mso[a-zA-Z]+/)) {
44829 node.className = cna.length ? cna.join(' ') : '';
44831 node.removeAttribute("class");
44835 if (node.hasAttribute("lang")) {
44836 node.removeAttribute("lang");
44839 if (node.hasAttribute("style")) {
44841 var styles = node.getAttribute("style").split(";");
44843 Roo.each(styles, function(s) {
44844 if (!s.match(/:/)) {
44847 var kv = s.split(":");
44848 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44851 // what ever is left... we allow.
44854 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44855 if (!nstyle.length) {
44856 node.removeAttribute('style');
44859 this.iterateChildren(node, this.cleanWord);
44865 * iterateChildren of a Node, calling fn each time, using this as the scole..
44866 * @param {DomNode} node node to iterate children of.
44867 * @param {Function} fn method of this class to call on each item.
44869 iterateChildren : function(node, fn)
44871 if (!node.childNodes.length) {
44874 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44875 fn.call(this, node.childNodes[i])
44881 * cleanTableWidths.
44883 * Quite often pasting from word etc.. results in tables with column and widths.
44884 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44887 cleanTableWidths : function(node)
44892 this.cleanTableWidths(this.doc.body);
44897 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44900 Roo.log(node.tagName);
44901 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44902 this.iterateChildren(node, this.cleanTableWidths);
44905 if (node.hasAttribute('width')) {
44906 node.removeAttribute('width');
44910 if (node.hasAttribute("style")) {
44913 var styles = node.getAttribute("style").split(";");
44915 Roo.each(styles, function(s) {
44916 if (!s.match(/:/)) {
44919 var kv = s.split(":");
44920 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44923 // what ever is left... we allow.
44926 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44927 if (!nstyle.length) {
44928 node.removeAttribute('style');
44932 this.iterateChildren(node, this.cleanTableWidths);
44940 domToHTML : function(currentElement, depth, nopadtext) {
44942 depth = depth || 0;
44943 nopadtext = nopadtext || false;
44945 if (!currentElement) {
44946 return this.domToHTML(this.doc.body);
44949 //Roo.log(currentElement);
44951 var allText = false;
44952 var nodeName = currentElement.nodeName;
44953 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44955 if (nodeName == '#text') {
44957 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44962 if (nodeName != 'BODY') {
44965 // Prints the node tagName, such as <A>, <IMG>, etc
44968 for(i = 0; i < currentElement.attributes.length;i++) {
44970 var aname = currentElement.attributes.item(i).name;
44971 if (!currentElement.attributes.item(i).value.length) {
44974 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44977 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44986 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44989 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44994 // Traverse the tree
44996 var currentElementChild = currentElement.childNodes.item(i);
44997 var allText = true;
44998 var innerHTML = '';
45000 while (currentElementChild) {
45001 // Formatting code (indent the tree so it looks nice on the screen)
45002 var nopad = nopadtext;
45003 if (lastnode == 'SPAN') {
45007 if (currentElementChild.nodeName == '#text') {
45008 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
45009 toadd = nopadtext ? toadd : toadd.trim();
45010 if (!nopad && toadd.length > 80) {
45011 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
45013 innerHTML += toadd;
45016 currentElementChild = currentElement.childNodes.item(i);
45022 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
45024 // Recursively traverse the tree structure of the child node
45025 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
45026 lastnode = currentElementChild.nodeName;
45028 currentElementChild=currentElement.childNodes.item(i);
45034 // The remaining code is mostly for formatting the tree
45035 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
45040 ret+= "</"+tagName+">";
45046 applyBlacklists : function()
45048 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
45049 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
45053 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
45054 if (b.indexOf(tag) > -1) {
45057 this.white.push(tag);
45061 Roo.each(w, function(tag) {
45062 if (b.indexOf(tag) > -1) {
45065 if (this.white.indexOf(tag) > -1) {
45068 this.white.push(tag);
45073 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
45074 if (w.indexOf(tag) > -1) {
45077 this.black.push(tag);
45081 Roo.each(b, function(tag) {
45082 if (w.indexOf(tag) > -1) {
45085 if (this.black.indexOf(tag) > -1) {
45088 this.black.push(tag);
45093 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45094 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45098 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45099 if (b.indexOf(tag) > -1) {
45102 this.cwhite.push(tag);
45106 Roo.each(w, function(tag) {
45107 if (b.indexOf(tag) > -1) {
45110 if (this.cwhite.indexOf(tag) > -1) {
45113 this.cwhite.push(tag);
45118 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45119 if (w.indexOf(tag) > -1) {
45122 this.cblack.push(tag);
45126 Roo.each(b, function(tag) {
45127 if (w.indexOf(tag) > -1) {
45130 if (this.cblack.indexOf(tag) > -1) {
45133 this.cblack.push(tag);
45138 setStylesheets : function(stylesheets)
45140 if(typeof(stylesheets) == 'string'){
45141 Roo.get(this.iframe.contentDocument.head).createChild({
45143 rel : 'stylesheet',
45152 Roo.each(stylesheets, function(s) {
45157 Roo.get(_this.iframe.contentDocument.head).createChild({
45159 rel : 'stylesheet',
45168 removeStylesheets : function()
45172 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45177 setStyle : function(style)
45179 Roo.get(this.iframe.contentDocument.head).createChild({
45188 // hide stuff that is not compatible
45202 * @event specialkey
45206 * @cfg {String} fieldClass @hide
45209 * @cfg {String} focusClass @hide
45212 * @cfg {String} autoCreate @hide
45215 * @cfg {String} inputType @hide
45218 * @cfg {String} invalidClass @hide
45221 * @cfg {String} invalidText @hide
45224 * @cfg {String} msgFx @hide
45227 * @cfg {String} validateOnBlur @hide
45231 Roo.HtmlEditorCore.white = [
45232 'area', 'br', 'img', 'input', 'hr', 'wbr',
45234 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45235 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45236 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45237 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45238 'table', 'ul', 'xmp',
45240 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45243 'dir', 'menu', 'ol', 'ul', 'dl',
45249 Roo.HtmlEditorCore.black = [
45250 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45252 'base', 'basefont', 'bgsound', 'blink', 'body',
45253 'frame', 'frameset', 'head', 'html', 'ilayer',
45254 'iframe', 'layer', 'link', 'meta', 'object',
45255 'script', 'style' ,'title', 'xml' // clean later..
45257 Roo.HtmlEditorCore.clean = [
45258 'script', 'style', 'title', 'xml'
45260 Roo.HtmlEditorCore.remove = [
45265 Roo.HtmlEditorCore.ablack = [
45269 Roo.HtmlEditorCore.aclean = [
45270 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45274 Roo.HtmlEditorCore.pwhite= [
45275 'http', 'https', 'mailto'
45278 // white listed style attributes.
45279 Roo.HtmlEditorCore.cwhite= [
45280 // 'text-align', /// default is to allow most things..
45286 // black listed style attributes.
45287 Roo.HtmlEditorCore.cblack= [
45288 // 'font-size' -- this can be set by the project
45292 Roo.HtmlEditorCore.swapCodes =[
45293 [ 8211, "–" ],
45294 [ 8212, "—" ],
45303 //<script type="text/javascript">
45306 * Ext JS Library 1.1.1
45307 * Copyright(c) 2006-2007, Ext JS, LLC.
45313 Roo.form.HtmlEditor = function(config){
45317 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45319 if (!this.toolbars) {
45320 this.toolbars = [];
45322 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45328 * @class Roo.form.HtmlEditor
45329 * @extends Roo.form.Field
45330 * Provides a lightweight HTML Editor component.
45332 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45334 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45335 * supported by this editor.</b><br/><br/>
45336 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45337 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45339 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45341 * @cfg {Boolean} clearUp
45345 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45350 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45355 * @cfg {Number} height (in pixels)
45359 * @cfg {Number} width (in pixels)
45364 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45367 stylesheets: false,
45371 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45376 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45382 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45387 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45395 // private properties
45396 validationEvent : false,
45398 initialized : false,
45401 onFocus : Roo.emptyFn,
45403 hideMode:'offsets',
45405 actionMode : 'container', // defaults to hiding it...
45407 defaultAutoCreate : { // modified by initCompnoent..
45409 style:"width:500px;height:300px;",
45410 autocomplete: "new-password"
45414 initComponent : function(){
45417 * @event initialize
45418 * Fires when the editor is fully initialized (including the iframe)
45419 * @param {HtmlEditor} this
45424 * Fires when the editor is first receives the focus. Any insertion must wait
45425 * until after this event.
45426 * @param {HtmlEditor} this
45430 * @event beforesync
45431 * Fires before the textarea is updated with content from the editor iframe. Return false
45432 * to cancel the sync.
45433 * @param {HtmlEditor} this
45434 * @param {String} html
45438 * @event beforepush
45439 * Fires before the iframe editor is updated with content from the textarea. Return false
45440 * to cancel the push.
45441 * @param {HtmlEditor} this
45442 * @param {String} html
45447 * Fires when the textarea is updated with content from the editor iframe.
45448 * @param {HtmlEditor} this
45449 * @param {String} html
45454 * Fires when the iframe editor is updated with content from the textarea.
45455 * @param {HtmlEditor} this
45456 * @param {String} html
45460 * @event editmodechange
45461 * Fires when the editor switches edit modes
45462 * @param {HtmlEditor} this
45463 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45465 editmodechange: true,
45467 * @event editorevent
45468 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45469 * @param {HtmlEditor} this
45473 * @event firstfocus
45474 * Fires when on first focus - needed by toolbars..
45475 * @param {HtmlEditor} this
45480 * Auto save the htmlEditor value as a file into Events
45481 * @param {HtmlEditor} this
45485 * @event savedpreview
45486 * preview the saved version of htmlEditor
45487 * @param {HtmlEditor} this
45489 savedpreview: true,
45492 * @event stylesheetsclick
45493 * Fires when press the Sytlesheets button
45494 * @param {Roo.HtmlEditorCore} this
45496 stylesheetsclick: true
45498 this.defaultAutoCreate = {
45500 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45501 autocomplete: "new-password"
45506 * Protected method that will not generally be called directly. It
45507 * is called when the editor creates its toolbar. Override this method if you need to
45508 * add custom toolbar buttons.
45509 * @param {HtmlEditor} editor
45511 createToolbar : function(editor){
45512 Roo.log("create toolbars");
45513 if (!editor.toolbars || !editor.toolbars.length) {
45514 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45517 for (var i =0 ; i < editor.toolbars.length;i++) {
45518 editor.toolbars[i] = Roo.factory(
45519 typeof(editor.toolbars[i]) == 'string' ?
45520 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45521 Roo.form.HtmlEditor);
45522 editor.toolbars[i].init(editor);
45530 onRender : function(ct, position)
45533 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45535 this.wrap = this.el.wrap({
45536 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45539 this.editorcore.onRender(ct, position);
45541 if (this.resizable) {
45542 this.resizeEl = new Roo.Resizable(this.wrap, {
45546 minHeight : this.height,
45547 height: this.height,
45548 handles : this.resizable,
45551 resize : function(r, w, h) {
45552 _t.onResize(w,h); // -something
45558 this.createToolbar(this);
45562 this.setSize(this.wrap.getSize());
45564 if (this.resizeEl) {
45565 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45566 // should trigger onReize..
45569 this.keyNav = new Roo.KeyNav(this.el, {
45571 "tab" : function(e){
45572 e.preventDefault();
45574 var value = this.getValue();
45576 var start = this.el.dom.selectionStart;
45577 var end = this.el.dom.selectionEnd;
45581 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45582 this.el.dom.setSelectionRange(end + 1, end + 1);
45586 var f = value.substring(0, start).split("\t");
45588 if(f.pop().length != 0){
45592 this.setValue(f.join("\t") + value.substring(end));
45593 this.el.dom.setSelectionRange(start - 1, start - 1);
45597 "home" : function(e){
45598 e.preventDefault();
45600 var curr = this.el.dom.selectionStart;
45601 var lines = this.getValue().split("\n");
45608 this.el.dom.setSelectionRange(0, 0);
45614 for (var i = 0; i < lines.length;i++) {
45615 pos += lines[i].length;
45625 pos -= lines[i].length;
45631 this.el.dom.setSelectionRange(pos, pos);
45635 this.el.dom.selectionStart = pos;
45636 this.el.dom.selectionEnd = curr;
45639 "end" : function(e){
45640 e.preventDefault();
45642 var curr = this.el.dom.selectionStart;
45643 var lines = this.getValue().split("\n");
45650 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45656 for (var i = 0; i < lines.length;i++) {
45658 pos += lines[i].length;
45672 this.el.dom.setSelectionRange(pos, pos);
45676 this.el.dom.selectionStart = curr;
45677 this.el.dom.selectionEnd = pos;
45682 doRelay : function(foo, bar, hname){
45683 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45689 // if(this.autosave && this.w){
45690 // this.autoSaveFn = setInterval(this.autosave, 1000);
45695 onResize : function(w, h)
45697 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45702 if(typeof w == 'number'){
45703 var aw = w - this.wrap.getFrameWidth('lr');
45704 this.el.setWidth(this.adjustWidth('textarea', aw));
45707 if(typeof h == 'number'){
45709 for (var i =0; i < this.toolbars.length;i++) {
45710 // fixme - ask toolbars for heights?
45711 tbh += this.toolbars[i].tb.el.getHeight();
45712 if (this.toolbars[i].footer) {
45713 tbh += this.toolbars[i].footer.el.getHeight();
45720 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45721 ah -= 5; // knock a few pixes off for look..
45723 this.el.setHeight(this.adjustWidth('textarea', ah));
45727 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45728 this.editorcore.onResize(ew,eh);
45733 * Toggles the editor between standard and source edit mode.
45734 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45736 toggleSourceEdit : function(sourceEditMode)
45738 this.editorcore.toggleSourceEdit(sourceEditMode);
45740 if(this.editorcore.sourceEditMode){
45741 Roo.log('editor - showing textarea');
45744 // Roo.log(this.syncValue());
45745 this.editorcore.syncValue();
45746 this.el.removeClass('x-hidden');
45747 this.el.dom.removeAttribute('tabIndex');
45750 for (var i = 0; i < this.toolbars.length; i++) {
45751 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45752 this.toolbars[i].tb.hide();
45753 this.toolbars[i].footer.hide();
45758 Roo.log('editor - hiding textarea');
45760 // Roo.log(this.pushValue());
45761 this.editorcore.pushValue();
45763 this.el.addClass('x-hidden');
45764 this.el.dom.setAttribute('tabIndex', -1);
45766 for (var i = 0; i < this.toolbars.length; i++) {
45767 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45768 this.toolbars[i].tb.show();
45769 this.toolbars[i].footer.show();
45773 //this.deferFocus();
45776 this.setSize(this.wrap.getSize());
45777 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45779 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45782 // private (for BoxComponent)
45783 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45785 // private (for BoxComponent)
45786 getResizeEl : function(){
45790 // private (for BoxComponent)
45791 getPositionEl : function(){
45796 initEvents : function(){
45797 this.originalValue = this.getValue();
45801 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45804 markInvalid : Roo.emptyFn,
45806 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45809 clearInvalid : Roo.emptyFn,
45811 setValue : function(v){
45812 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45813 this.editorcore.pushValue();
45818 deferFocus : function(){
45819 this.focus.defer(10, this);
45823 focus : function(){
45824 this.editorcore.focus();
45830 onDestroy : function(){
45836 for (var i =0; i < this.toolbars.length;i++) {
45837 // fixme - ask toolbars for heights?
45838 this.toolbars[i].onDestroy();
45841 this.wrap.dom.innerHTML = '';
45842 this.wrap.remove();
45847 onFirstFocus : function(){
45848 //Roo.log("onFirstFocus");
45849 this.editorcore.onFirstFocus();
45850 for (var i =0; i < this.toolbars.length;i++) {
45851 this.toolbars[i].onFirstFocus();
45857 syncValue : function()
45859 this.editorcore.syncValue();
45862 pushValue : function()
45864 this.editorcore.pushValue();
45867 setStylesheets : function(stylesheets)
45869 this.editorcore.setStylesheets(stylesheets);
45872 removeStylesheets : function()
45874 this.editorcore.removeStylesheets();
45878 // hide stuff that is not compatible
45892 * @event specialkey
45896 * @cfg {String} fieldClass @hide
45899 * @cfg {String} focusClass @hide
45902 * @cfg {String} autoCreate @hide
45905 * @cfg {String} inputType @hide
45908 * @cfg {String} invalidClass @hide
45911 * @cfg {String} invalidText @hide
45914 * @cfg {String} msgFx @hide
45917 * @cfg {String} validateOnBlur @hide
45921 // <script type="text/javascript">
45924 * Ext JS Library 1.1.1
45925 * Copyright(c) 2006-2007, Ext JS, LLC.
45931 * @class Roo.form.HtmlEditorToolbar1
45936 new Roo.form.HtmlEditor({
45939 new Roo.form.HtmlEditorToolbar1({
45940 disable : { fonts: 1 , format: 1, ..., ... , ...],
45946 * @cfg {Object} disable List of elements to disable..
45947 * @cfg {Array} btns List of additional buttons.
45951 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45954 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45957 Roo.apply(this, config);
45959 // default disabled, based on 'good practice'..
45960 this.disable = this.disable || {};
45961 Roo.applyIf(this.disable, {
45964 specialElements : true
45968 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45969 // dont call parent... till later.
45972 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45979 editorcore : false,
45981 * @cfg {Object} disable List of toolbar elements to disable
45988 * @cfg {String} createLinkText The default text for the create link prompt
45990 createLinkText : 'Please enter the URL for the link:',
45992 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45994 defaultLinkValue : 'http:/'+'/',
45998 * @cfg {Array} fontFamilies An array of available font families
46016 // "á" , ?? a acute?
46021 "°" // , // degrees
46023 // "é" , // e ecute
46024 // "ú" , // u ecute?
46027 specialElements : [
46029 text: "Insert Table",
46032 ihtml : '<table><tr><td>Cell</td></tr></table>'
46036 text: "Insert Image",
46039 ihtml : '<img src="about:blank"/>'
46048 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
46049 "input:submit", "input:button", "select", "textarea", "label" ],
46052 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
46054 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
46063 * @cfg {String} defaultFont default font to use.
46065 defaultFont: 'tahoma',
46067 fontSelect : false,
46070 formatCombo : false,
46072 init : function(editor)
46074 this.editor = editor;
46075 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46076 var editorcore = this.editorcore;
46080 var fid = editorcore.frameId;
46082 function btn(id, toggle, handler){
46083 var xid = fid + '-'+ id ;
46087 cls : 'x-btn-icon x-edit-'+id,
46088 enableToggle:toggle !== false,
46089 scope: _t, // was editor...
46090 handler:handler||_t.relayBtnCmd,
46091 clickEvent:'mousedown',
46092 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46099 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46101 // stop form submits
46102 tb.el.on('click', function(e){
46103 e.preventDefault(); // what does this do?
46106 if(!this.disable.font) { // && !Roo.isSafari){
46107 /* why no safari for fonts
46108 editor.fontSelect = tb.el.createChild({
46111 cls:'x-font-select',
46112 html: this.createFontOptions()
46115 editor.fontSelect.on('change', function(){
46116 var font = editor.fontSelect.dom.value;
46117 editor.relayCmd('fontname', font);
46118 editor.deferFocus();
46122 editor.fontSelect.dom,
46128 if(!this.disable.formats){
46129 this.formatCombo = new Roo.form.ComboBox({
46130 store: new Roo.data.SimpleStore({
46133 data : this.formats // from states.js
46137 //autoCreate : {tag: "div", size: "20"},
46138 displayField:'tag',
46142 triggerAction: 'all',
46143 emptyText:'Add tag',
46144 selectOnFocus:true,
46147 'select': function(c, r, i) {
46148 editorcore.insertTag(r.get('tag'));
46154 tb.addField(this.formatCombo);
46158 if(!this.disable.format){
46163 btn('strikethrough')
46166 if(!this.disable.fontSize){
46171 btn('increasefontsize', false, editorcore.adjustFont),
46172 btn('decreasefontsize', false, editorcore.adjustFont)
46177 if(!this.disable.colors){
46180 id:editorcore.frameId +'-forecolor',
46181 cls:'x-btn-icon x-edit-forecolor',
46182 clickEvent:'mousedown',
46183 tooltip: this.buttonTips['forecolor'] || undefined,
46185 menu : new Roo.menu.ColorMenu({
46186 allowReselect: true,
46187 focus: Roo.emptyFn,
46190 selectHandler: function(cp, color){
46191 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46192 editor.deferFocus();
46195 clickEvent:'mousedown'
46198 id:editorcore.frameId +'backcolor',
46199 cls:'x-btn-icon x-edit-backcolor',
46200 clickEvent:'mousedown',
46201 tooltip: this.buttonTips['backcolor'] || undefined,
46203 menu : new Roo.menu.ColorMenu({
46204 focus: Roo.emptyFn,
46207 allowReselect: true,
46208 selectHandler: function(cp, color){
46210 editorcore.execCmd('useCSS', false);
46211 editorcore.execCmd('hilitecolor', color);
46212 editorcore.execCmd('useCSS', true);
46213 editor.deferFocus();
46215 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46216 Roo.isSafari || Roo.isIE ? '#'+color : color);
46217 editor.deferFocus();
46221 clickEvent:'mousedown'
46226 // now add all the items...
46229 if(!this.disable.alignments){
46232 btn('justifyleft'),
46233 btn('justifycenter'),
46234 btn('justifyright')
46238 //if(!Roo.isSafari){
46239 if(!this.disable.links){
46242 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46246 if(!this.disable.lists){
46249 btn('insertorderedlist'),
46250 btn('insertunorderedlist')
46253 if(!this.disable.sourceEdit){
46256 btn('sourceedit', true, function(btn){
46257 this.toggleSourceEdit(btn.pressed);
46264 // special menu.. - needs to be tidied up..
46265 if (!this.disable.special) {
46268 cls: 'x-edit-none',
46274 for (var i =0; i < this.specialChars.length; i++) {
46275 smenu.menu.items.push({
46277 html: this.specialChars[i],
46278 handler: function(a,b) {
46279 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46280 //editor.insertAtCursor(a.html);
46294 if (!this.disable.cleanStyles) {
46296 cls: 'x-btn-icon x-btn-clear',
46302 for (var i =0; i < this.cleanStyles.length; i++) {
46303 cmenu.menu.items.push({
46304 actiontype : this.cleanStyles[i],
46305 html: 'Remove ' + this.cleanStyles[i],
46306 handler: function(a,b) {
46309 var c = Roo.get(editorcore.doc.body);
46310 c.select('[style]').each(function(s) {
46311 s.dom.style.removeProperty(a.actiontype);
46313 editorcore.syncValue();
46318 cmenu.menu.items.push({
46319 actiontype : 'tablewidths',
46320 html: 'Remove Table Widths',
46321 handler: function(a,b) {
46322 editorcore.cleanTableWidths();
46323 editorcore.syncValue();
46327 cmenu.menu.items.push({
46328 actiontype : 'word',
46329 html: 'Remove MS Word Formating',
46330 handler: function(a,b) {
46331 editorcore.cleanWord();
46332 editorcore.syncValue();
46337 cmenu.menu.items.push({
46338 actiontype : 'all',
46339 html: 'Remove All Styles',
46340 handler: function(a,b) {
46342 var c = Roo.get(editorcore.doc.body);
46343 c.select('[style]').each(function(s) {
46344 s.dom.removeAttribute('style');
46346 editorcore.syncValue();
46351 cmenu.menu.items.push({
46352 actiontype : 'all',
46353 html: 'Remove All CSS Classes',
46354 handler: function(a,b) {
46356 var c = Roo.get(editorcore.doc.body);
46357 c.select('[class]').each(function(s) {
46358 s.dom.removeAttribute('class');
46360 editorcore.cleanWord();
46361 editorcore.syncValue();
46366 cmenu.menu.items.push({
46367 actiontype : 'tidy',
46368 html: 'Tidy HTML Source',
46369 handler: function(a,b) {
46370 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46371 editorcore.syncValue();
46380 if (!this.disable.specialElements) {
46383 cls: 'x-edit-none',
46388 for (var i =0; i < this.specialElements.length; i++) {
46389 semenu.menu.items.push(
46391 handler: function(a,b) {
46392 editor.insertAtCursor(this.ihtml);
46394 }, this.specialElements[i])
46406 for(var i =0; i< this.btns.length;i++) {
46407 var b = Roo.factory(this.btns[i],Roo.form);
46408 b.cls = 'x-edit-none';
46410 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46411 b.cls += ' x-init-enable';
46414 b.scope = editorcore;
46422 // disable everything...
46424 this.tb.items.each(function(item){
46427 item.id != editorcore.frameId+ '-sourceedit' &&
46428 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46434 this.rendered = true;
46436 // the all the btns;
46437 editor.on('editorevent', this.updateToolbar, this);
46438 // other toolbars need to implement this..
46439 //editor.on('editmodechange', this.updateToolbar, this);
46443 relayBtnCmd : function(btn) {
46444 this.editorcore.relayCmd(btn.cmd);
46446 // private used internally
46447 createLink : function(){
46448 Roo.log("create link?");
46449 var url = prompt(this.createLinkText, this.defaultLinkValue);
46450 if(url && url != 'http:/'+'/'){
46451 this.editorcore.relayCmd('createlink', url);
46457 * Protected method that will not generally be called directly. It triggers
46458 * a toolbar update by reading the markup state of the current selection in the editor.
46460 updateToolbar: function(){
46462 if(!this.editorcore.activated){
46463 this.editor.onFirstFocus();
46467 var btns = this.tb.items.map,
46468 doc = this.editorcore.doc,
46469 frameId = this.editorcore.frameId;
46471 if(!this.disable.font && !Roo.isSafari){
46473 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46474 if(name != this.fontSelect.dom.value){
46475 this.fontSelect.dom.value = name;
46479 if(!this.disable.format){
46480 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46481 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46482 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46483 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46485 if(!this.disable.alignments){
46486 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46487 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46488 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46490 if(!Roo.isSafari && !this.disable.lists){
46491 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46492 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46495 var ans = this.editorcore.getAllAncestors();
46496 if (this.formatCombo) {
46499 var store = this.formatCombo.store;
46500 this.formatCombo.setValue("");
46501 for (var i =0; i < ans.length;i++) {
46502 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46504 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46512 // hides menus... - so this cant be on a menu...
46513 Roo.menu.MenuMgr.hideAll();
46515 //this.editorsyncValue();
46519 createFontOptions : function(){
46520 var buf = [], fs = this.fontFamilies, ff, lc;
46524 for(var i = 0, len = fs.length; i< len; i++){
46526 lc = ff.toLowerCase();
46528 '<option value="',lc,'" style="font-family:',ff,';"',
46529 (this.defaultFont == lc ? ' selected="true">' : '>'),
46534 return buf.join('');
46537 toggleSourceEdit : function(sourceEditMode){
46539 Roo.log("toolbar toogle");
46540 if(sourceEditMode === undefined){
46541 sourceEditMode = !this.sourceEditMode;
46543 this.sourceEditMode = sourceEditMode === true;
46544 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46545 // just toggle the button?
46546 if(btn.pressed !== this.sourceEditMode){
46547 btn.toggle(this.sourceEditMode);
46551 if(sourceEditMode){
46552 Roo.log("disabling buttons");
46553 this.tb.items.each(function(item){
46554 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46560 Roo.log("enabling buttons");
46561 if(this.editorcore.initialized){
46562 this.tb.items.each(function(item){
46568 Roo.log("calling toggole on editor");
46569 // tell the editor that it's been pressed..
46570 this.editor.toggleSourceEdit(sourceEditMode);
46574 * Object collection of toolbar tooltips for the buttons in the editor. The key
46575 * is the command id associated with that button and the value is a valid QuickTips object.
46580 title: 'Bold (Ctrl+B)',
46581 text: 'Make the selected text bold.',
46582 cls: 'x-html-editor-tip'
46585 title: 'Italic (Ctrl+I)',
46586 text: 'Make the selected text italic.',
46587 cls: 'x-html-editor-tip'
46595 title: 'Bold (Ctrl+B)',
46596 text: 'Make the selected text bold.',
46597 cls: 'x-html-editor-tip'
46600 title: 'Italic (Ctrl+I)',
46601 text: 'Make the selected text italic.',
46602 cls: 'x-html-editor-tip'
46605 title: 'Underline (Ctrl+U)',
46606 text: 'Underline the selected text.',
46607 cls: 'x-html-editor-tip'
46610 title: 'Strikethrough',
46611 text: 'Strikethrough the selected text.',
46612 cls: 'x-html-editor-tip'
46614 increasefontsize : {
46615 title: 'Grow Text',
46616 text: 'Increase the font size.',
46617 cls: 'x-html-editor-tip'
46619 decreasefontsize : {
46620 title: 'Shrink Text',
46621 text: 'Decrease the font size.',
46622 cls: 'x-html-editor-tip'
46625 title: 'Text Highlight Color',
46626 text: 'Change the background color of the selected text.',
46627 cls: 'x-html-editor-tip'
46630 title: 'Font Color',
46631 text: 'Change the color of the selected text.',
46632 cls: 'x-html-editor-tip'
46635 title: 'Align Text Left',
46636 text: 'Align text to the left.',
46637 cls: 'x-html-editor-tip'
46640 title: 'Center Text',
46641 text: 'Center text in the editor.',
46642 cls: 'x-html-editor-tip'
46645 title: 'Align Text Right',
46646 text: 'Align text to the right.',
46647 cls: 'x-html-editor-tip'
46649 insertunorderedlist : {
46650 title: 'Bullet List',
46651 text: 'Start a bulleted list.',
46652 cls: 'x-html-editor-tip'
46654 insertorderedlist : {
46655 title: 'Numbered List',
46656 text: 'Start a numbered list.',
46657 cls: 'x-html-editor-tip'
46660 title: 'Hyperlink',
46661 text: 'Make the selected text a hyperlink.',
46662 cls: 'x-html-editor-tip'
46665 title: 'Source Edit',
46666 text: 'Switch to source editing mode.',
46667 cls: 'x-html-editor-tip'
46671 onDestroy : function(){
46674 this.tb.items.each(function(item){
46676 item.menu.removeAll();
46678 item.menu.el.destroy();
46686 onFirstFocus: function() {
46687 this.tb.items.each(function(item){
46696 // <script type="text/javascript">
46699 * Ext JS Library 1.1.1
46700 * Copyright(c) 2006-2007, Ext JS, LLC.
46707 * @class Roo.form.HtmlEditor.ToolbarContext
46712 new Roo.form.HtmlEditor({
46715 { xtype: 'ToolbarStandard', styles : {} }
46716 { xtype: 'ToolbarContext', disable : {} }
46722 * @config : {Object} disable List of elements to disable.. (not done yet.)
46723 * @config : {Object} styles Map of styles available.
46727 Roo.form.HtmlEditor.ToolbarContext = function(config)
46730 Roo.apply(this, config);
46731 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46732 // dont call parent... till later.
46733 this.styles = this.styles || {};
46738 Roo.form.HtmlEditor.ToolbarContext.types = {
46750 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46816 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46821 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46831 style : 'fontFamily',
46832 displayField: 'display',
46833 optname : 'font-family',
46882 // should we really allow this??
46883 // should this just be
46894 style : 'fontFamily',
46895 displayField: 'display',
46896 optname : 'font-family',
46903 style : 'fontFamily',
46904 displayField: 'display',
46905 optname : 'font-family',
46912 style : 'fontFamily',
46913 displayField: 'display',
46914 optname : 'font-family',
46925 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46926 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46928 Roo.form.HtmlEditor.ToolbarContext.options = {
46930 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46931 [ 'Courier New', 'Courier New'],
46932 [ 'Tahoma', 'Tahoma'],
46933 [ 'Times New Roman,serif', 'Times'],
46934 [ 'Verdana','Verdana' ]
46938 // fixme - these need to be configurable..
46941 //Roo.form.HtmlEditor.ToolbarContext.types
46944 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46951 editorcore : false,
46953 * @cfg {Object} disable List of toolbar elements to disable
46958 * @cfg {Object} styles List of styles
46959 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46961 * These must be defined in the page, so they get rendered correctly..
46972 init : function(editor)
46974 this.editor = editor;
46975 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46976 var editorcore = this.editorcore;
46978 var fid = editorcore.frameId;
46980 function btn(id, toggle, handler){
46981 var xid = fid + '-'+ id ;
46985 cls : 'x-btn-icon x-edit-'+id,
46986 enableToggle:toggle !== false,
46987 scope: editorcore, // was editor...
46988 handler:handler||editorcore.relayBtnCmd,
46989 clickEvent:'mousedown',
46990 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46994 // create a new element.
46995 var wdiv = editor.wrap.createChild({
46997 }, editor.wrap.dom.firstChild.nextSibling, true);
46999 // can we do this more than once??
47001 // stop form submits
47004 // disable everything...
47005 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47006 this.toolbars = {};
47008 for (var i in ty) {
47010 this.toolbars[i] = this.buildToolbar(ty[i],i);
47012 this.tb = this.toolbars.BODY;
47014 this.buildFooter();
47015 this.footer.show();
47016 editor.on('hide', function( ) { this.footer.hide() }, this);
47017 editor.on('show', function( ) { this.footer.show() }, this);
47020 this.rendered = true;
47022 // the all the btns;
47023 editor.on('editorevent', this.updateToolbar, this);
47024 // other toolbars need to implement this..
47025 //editor.on('editmodechange', this.updateToolbar, this);
47031 * Protected method that will not generally be called directly. It triggers
47032 * a toolbar update by reading the markup state of the current selection in the editor.
47034 * Note you can force an update by calling on('editorevent', scope, false)
47036 updateToolbar: function(editor,ev,sel){
47039 // capture mouse up - this is handy for selecting images..
47040 // perhaps should go somewhere else...
47041 if(!this.editorcore.activated){
47042 this.editor.onFirstFocus();
47048 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
47049 // selectNode - might want to handle IE?
47051 (ev.type == 'mouseup' || ev.type == 'click' ) &&
47052 ev.target && ev.target.tagName == 'IMG') {
47053 // they have click on an image...
47054 // let's see if we can change the selection...
47057 var nodeRange = sel.ownerDocument.createRange();
47059 nodeRange.selectNode(sel);
47061 nodeRange.selectNodeContents(sel);
47063 //nodeRange.collapse(true);
47064 var s = this.editorcore.win.getSelection();
47065 s.removeAllRanges();
47066 s.addRange(nodeRange);
47070 var updateFooter = sel ? false : true;
47073 var ans = this.editorcore.getAllAncestors();
47076 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47079 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47080 sel = sel ? sel : this.editorcore.doc.body;
47081 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47084 // pick a menu that exists..
47085 var tn = sel.tagName.toUpperCase();
47086 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47088 tn = sel.tagName.toUpperCase();
47090 var lastSel = this.tb.selectedNode;
47092 this.tb.selectedNode = sel;
47094 // if current menu does not match..
47096 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47099 ///console.log("show: " + tn);
47100 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47103 this.tb.items.first().el.innerHTML = tn + ': ';
47106 // update attributes
47107 if (this.tb.fields) {
47108 this.tb.fields.each(function(e) {
47110 e.setValue(sel.style[e.stylename]);
47113 e.setValue(sel.getAttribute(e.attrname));
47117 var hasStyles = false;
47118 for(var i in this.styles) {
47125 var st = this.tb.fields.item(0);
47127 st.store.removeAll();
47130 var cn = sel.className.split(/\s+/);
47133 if (this.styles['*']) {
47135 Roo.each(this.styles['*'], function(v) {
47136 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47139 if (this.styles[tn]) {
47140 Roo.each(this.styles[tn], function(v) {
47141 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47145 st.store.loadData(avs);
47149 // flag our selected Node.
47150 this.tb.selectedNode = sel;
47153 Roo.menu.MenuMgr.hideAll();
47157 if (!updateFooter) {
47158 //this.footDisp.dom.innerHTML = '';
47161 // update the footer
47165 this.footerEls = ans.reverse();
47166 Roo.each(this.footerEls, function(a,i) {
47167 if (!a) { return; }
47168 html += html.length ? ' > ' : '';
47170 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47175 var sz = this.footDisp.up('td').getSize();
47176 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47177 this.footDisp.dom.style.marginLeft = '5px';
47179 this.footDisp.dom.style.overflow = 'hidden';
47181 this.footDisp.dom.innerHTML = html;
47183 //this.editorsyncValue();
47190 onDestroy : function(){
47193 this.tb.items.each(function(item){
47195 item.menu.removeAll();
47197 item.menu.el.destroy();
47205 onFirstFocus: function() {
47206 // need to do this for all the toolbars..
47207 this.tb.items.each(function(item){
47211 buildToolbar: function(tlist, nm)
47213 var editor = this.editor;
47214 var editorcore = this.editorcore;
47215 // create a new element.
47216 var wdiv = editor.wrap.createChild({
47218 }, editor.wrap.dom.firstChild.nextSibling, true);
47221 var tb = new Roo.Toolbar(wdiv);
47224 tb.add(nm+ ": ");
47227 for(var i in this.styles) {
47232 if (styles && styles.length) {
47234 // this needs a multi-select checkbox...
47235 tb.addField( new Roo.form.ComboBox({
47236 store: new Roo.data.SimpleStore({
47238 fields: ['val', 'selected'],
47241 name : '-roo-edit-className',
47242 attrname : 'className',
47243 displayField: 'val',
47247 triggerAction: 'all',
47248 emptyText:'Select Style',
47249 selectOnFocus:true,
47252 'select': function(c, r, i) {
47253 // initial support only for on class per el..
47254 tb.selectedNode.className = r ? r.get('val') : '';
47255 editorcore.syncValue();
47262 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47263 var tbops = tbc.options;
47265 for (var i in tlist) {
47267 var item = tlist[i];
47268 tb.add(item.title + ": ");
47271 //optname == used so you can configure the options available..
47272 var opts = item.opts ? item.opts : false;
47273 if (item.optname) {
47274 opts = tbops[item.optname];
47279 // opts == pulldown..
47280 tb.addField( new Roo.form.ComboBox({
47281 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47283 fields: ['val', 'display'],
47286 name : '-roo-edit-' + i,
47288 stylename : item.style ? item.style : false,
47289 displayField: item.displayField ? item.displayField : 'val',
47290 valueField : 'val',
47292 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47294 triggerAction: 'all',
47295 emptyText:'Select',
47296 selectOnFocus:true,
47297 width: item.width ? item.width : 130,
47299 'select': function(c, r, i) {
47301 tb.selectedNode.style[c.stylename] = r.get('val');
47304 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47313 tb.addField( new Roo.form.TextField({
47316 //allowBlank:false,
47321 tb.addField( new Roo.form.TextField({
47322 name: '-roo-edit-' + i,
47329 'change' : function(f, nv, ov) {
47330 tb.selectedNode.setAttribute(f.attrname, nv);
47331 editorcore.syncValue();
47344 text: 'Stylesheets',
47347 click : function ()
47349 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47357 text: 'Remove Tag',
47360 click : function ()
47363 // undo does not work.
47365 var sn = tb.selectedNode;
47367 var pn = sn.parentNode;
47369 var stn = sn.childNodes[0];
47370 var en = sn.childNodes[sn.childNodes.length - 1 ];
47371 while (sn.childNodes.length) {
47372 var node = sn.childNodes[0];
47373 sn.removeChild(node);
47375 pn.insertBefore(node, sn);
47378 pn.removeChild(sn);
47379 var range = editorcore.createRange();
47381 range.setStart(stn,0);
47382 range.setEnd(en,0); //????
47383 //range.selectNode(sel);
47386 var selection = editorcore.getSelection();
47387 selection.removeAllRanges();
47388 selection.addRange(range);
47392 //_this.updateToolbar(null, null, pn);
47393 _this.updateToolbar(null, null, null);
47394 _this.footDisp.dom.innerHTML = '';
47404 tb.el.on('click', function(e){
47405 e.preventDefault(); // what does this do?
47407 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47410 // dont need to disable them... as they will get hidden
47415 buildFooter : function()
47418 var fel = this.editor.wrap.createChild();
47419 this.footer = new Roo.Toolbar(fel);
47420 // toolbar has scrolly on left / right?
47421 var footDisp= new Roo.Toolbar.Fill();
47427 handler : function() {
47428 _t.footDisp.scrollTo('left',0,true)
47432 this.footer.add( footDisp );
47437 handler : function() {
47439 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47443 var fel = Roo.get(footDisp.el);
47444 fel.addClass('x-editor-context');
47445 this.footDispWrap = fel;
47446 this.footDispWrap.overflow = 'hidden';
47448 this.footDisp = fel.createChild();
47449 this.footDispWrap.on('click', this.onContextClick, this)
47453 onContextClick : function (ev,dom)
47455 ev.preventDefault();
47456 var cn = dom.className;
47458 if (!cn.match(/x-ed-loc-/)) {
47461 var n = cn.split('-').pop();
47462 var ans = this.footerEls;
47466 var range = this.editorcore.createRange();
47468 range.selectNodeContents(sel);
47469 //range.selectNode(sel);
47472 var selection = this.editorcore.getSelection();
47473 selection.removeAllRanges();
47474 selection.addRange(range);
47478 this.updateToolbar(null, null, sel);
47495 * Ext JS Library 1.1.1
47496 * Copyright(c) 2006-2007, Ext JS, LLC.
47498 * Originally Released Under LGPL - original licence link has changed is not relivant.
47501 * <script type="text/javascript">
47505 * @class Roo.form.BasicForm
47506 * @extends Roo.util.Observable
47507 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47509 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47510 * @param {Object} config Configuration options
47512 Roo.form.BasicForm = function(el, config){
47513 this.allItems = [];
47514 this.childForms = [];
47515 Roo.apply(this, config);
47517 * The Roo.form.Field items in this form.
47518 * @type MixedCollection
47522 this.items = new Roo.util.MixedCollection(false, function(o){
47523 return o.id || (o.id = Roo.id());
47527 * @event beforeaction
47528 * Fires before any action is performed. Return false to cancel the action.
47529 * @param {Form} this
47530 * @param {Action} action The action to be performed
47532 beforeaction: true,
47534 * @event actionfailed
47535 * Fires when an action fails.
47536 * @param {Form} this
47537 * @param {Action} action The action that failed
47539 actionfailed : true,
47541 * @event actioncomplete
47542 * Fires when an action is completed.
47543 * @param {Form} this
47544 * @param {Action} action The action that completed
47546 actioncomplete : true
47551 Roo.form.BasicForm.superclass.constructor.call(this);
47553 Roo.form.BasicForm.popover.apply();
47556 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47558 * @cfg {String} method
47559 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47562 * @cfg {DataReader} reader
47563 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47564 * This is optional as there is built-in support for processing JSON.
47567 * @cfg {DataReader} errorReader
47568 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47569 * This is completely optional as there is built-in support for processing JSON.
47572 * @cfg {String} url
47573 * The URL to use for form actions if one isn't supplied in the action options.
47576 * @cfg {Boolean} fileUpload
47577 * Set to true if this form is a file upload.
47581 * @cfg {Object} baseParams
47582 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47587 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47592 activeAction : null,
47595 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47596 * or setValues() data instead of when the form was first created.
47598 trackResetOnLoad : false,
47602 * childForms - used for multi-tab forms
47605 childForms : false,
47608 * allItems - full list of fields.
47614 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47615 * element by passing it or its id or mask the form itself by passing in true.
47618 waitMsgTarget : false,
47623 disableMask : false,
47626 * @cfg {Boolean} errorMask (true|false) default false
47631 * @cfg {Number} maskOffset Default 100
47636 initEl : function(el){
47637 this.el = Roo.get(el);
47638 this.id = this.el.id || Roo.id();
47639 this.el.on('submit', this.onSubmit, this);
47640 this.el.addClass('x-form');
47644 onSubmit : function(e){
47649 * Returns true if client-side validation on the form is successful.
47652 isValid : function(){
47654 var target = false;
47655 this.items.each(function(f){
47662 if(!target && f.el.isVisible(true)){
47667 if(this.errorMask && !valid){
47668 Roo.form.BasicForm.popover.mask(this, target);
47674 * Returns array of invalid form fields.
47678 invalidFields : function()
47681 this.items.each(function(f){
47694 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47697 isDirty : function(){
47699 this.items.each(function(f){
47709 * Returns true if any fields in this form have changed since their original load. (New version)
47713 hasChanged : function()
47716 this.items.each(function(f){
47717 if(f.hasChanged()){
47726 * Resets all hasChanged to 'false' -
47727 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47728 * So hasChanged storage is only to be used for this purpose
47731 resetHasChanged : function()
47733 this.items.each(function(f){
47734 f.resetHasChanged();
47741 * Performs a predefined action (submit or load) or custom actions you define on this form.
47742 * @param {String} actionName The name of the action type
47743 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47744 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47745 * accept other config options):
47747 Property Type Description
47748 ---------------- --------------- ----------------------------------------------------------------------------------
47749 url String The url for the action (defaults to the form's url)
47750 method String The form method to use (defaults to the form's method, or POST if not defined)
47751 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47752 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47753 validate the form on the client (defaults to false)
47755 * @return {BasicForm} this
47757 doAction : function(action, options){
47758 if(typeof action == 'string'){
47759 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47761 if(this.fireEvent('beforeaction', this, action) !== false){
47762 this.beforeAction(action);
47763 action.run.defer(100, action);
47769 * Shortcut to do a submit action.
47770 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47771 * @return {BasicForm} this
47773 submit : function(options){
47774 this.doAction('submit', options);
47779 * Shortcut to do a load action.
47780 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47781 * @return {BasicForm} this
47783 load : function(options){
47784 this.doAction('load', options);
47789 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47790 * @param {Record} record The record to edit
47791 * @return {BasicForm} this
47793 updateRecord : function(record){
47794 record.beginEdit();
47795 var fs = record.fields;
47796 fs.each(function(f){
47797 var field = this.findField(f.name);
47799 record.set(f.name, field.getValue());
47807 * Loads an Roo.data.Record into this form.
47808 * @param {Record} record The record to load
47809 * @return {BasicForm} this
47811 loadRecord : function(record){
47812 this.setValues(record.data);
47817 beforeAction : function(action){
47818 var o = action.options;
47820 if(!this.disableMask) {
47821 if(this.waitMsgTarget === true){
47822 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47823 }else if(this.waitMsgTarget){
47824 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47825 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47827 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47835 afterAction : function(action, success){
47836 this.activeAction = null;
47837 var o = action.options;
47839 if(!this.disableMask) {
47840 if(this.waitMsgTarget === true){
47842 }else if(this.waitMsgTarget){
47843 this.waitMsgTarget.unmask();
47845 Roo.MessageBox.updateProgress(1);
47846 Roo.MessageBox.hide();
47854 Roo.callback(o.success, o.scope, [this, action]);
47855 this.fireEvent('actioncomplete', this, action);
47859 // failure condition..
47860 // we have a scenario where updates need confirming.
47861 // eg. if a locking scenario exists..
47862 // we look for { errors : { needs_confirm : true }} in the response.
47864 (typeof(action.result) != 'undefined') &&
47865 (typeof(action.result.errors) != 'undefined') &&
47866 (typeof(action.result.errors.needs_confirm) != 'undefined')
47869 Roo.MessageBox.confirm(
47870 "Change requires confirmation",
47871 action.result.errorMsg,
47876 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47886 Roo.callback(o.failure, o.scope, [this, action]);
47887 // show an error message if no failed handler is set..
47888 if (!this.hasListener('actionfailed')) {
47889 Roo.MessageBox.alert("Error",
47890 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47891 action.result.errorMsg :
47892 "Saving Failed, please check your entries or try again"
47896 this.fireEvent('actionfailed', this, action);
47902 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47903 * @param {String} id The value to search for
47906 findField : function(id){
47907 var field = this.items.get(id);
47909 this.items.each(function(f){
47910 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47916 return field || null;
47920 * Add a secondary form to this one,
47921 * Used to provide tabbed forms. One form is primary, with hidden values
47922 * which mirror the elements from the other forms.
47924 * @param {Roo.form.Form} form to add.
47927 addForm : function(form)
47930 if (this.childForms.indexOf(form) > -1) {
47934 this.childForms.push(form);
47936 Roo.each(form.allItems, function (fe) {
47938 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
47939 if (this.findField(n)) { // already added..
47942 var add = new Roo.form.Hidden({
47945 add.render(this.el);
47952 * Mark fields in this form invalid in bulk.
47953 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
47954 * @return {BasicForm} this
47956 markInvalid : function(errors){
47957 if(errors instanceof Array){
47958 for(var i = 0, len = errors.length; i < len; i++){
47959 var fieldError = errors[i];
47960 var f = this.findField(fieldError.id);
47962 f.markInvalid(fieldError.msg);
47968 if(typeof errors[id] != 'function' && (field = this.findField(id))){
47969 field.markInvalid(errors[id]);
47973 Roo.each(this.childForms || [], function (f) {
47974 f.markInvalid(errors);
47981 * Set values for fields in this form in bulk.
47982 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
47983 * @return {BasicForm} this
47985 setValues : function(values){
47986 if(values instanceof Array){ // array of objects
47987 for(var i = 0, len = values.length; i < len; i++){
47989 var f = this.findField(v.id);
47991 f.setValue(v.value);
47992 if(this.trackResetOnLoad){
47993 f.originalValue = f.getValue();
47997 }else{ // object hash
48000 if(typeof values[id] != 'function' && (field = this.findField(id))){
48002 if (field.setFromData &&
48003 field.valueField &&
48004 field.displayField &&
48005 // combos' with local stores can
48006 // be queried via setValue()
48007 // to set their value..
48008 (field.store && !field.store.isLocal)
48012 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
48013 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
48014 field.setFromData(sd);
48017 field.setValue(values[id]);
48021 if(this.trackResetOnLoad){
48022 field.originalValue = field.getValue();
48027 this.resetHasChanged();
48030 Roo.each(this.childForms || [], function (f) {
48031 f.setValues(values);
48032 f.resetHasChanged();
48039 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
48040 * they are returned as an array.
48041 * @param {Boolean} asString
48044 getValues : function(asString){
48045 if (this.childForms) {
48046 // copy values from the child forms
48047 Roo.each(this.childForms, function (f) {
48048 this.setValues(f.getValues());
48053 if (typeof(FormData) != 'undefined' && asString !== true) {
48054 // this relies on a 'recent' version of chrome apparently...
48056 var fd = (new FormData(this.el.dom)).entries();
48058 var ent = fd.next();
48059 while (!ent.done) {
48060 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
48071 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
48072 if(asString === true){
48075 return Roo.urlDecode(fs);
48079 * Returns the fields in this form as an object with key/value pairs.
48080 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48083 getFieldValues : function(with_hidden)
48085 if (this.childForms) {
48086 // copy values from the child forms
48087 // should this call getFieldValues - probably not as we do not currently copy
48088 // hidden fields when we generate..
48089 Roo.each(this.childForms, function (f) {
48090 this.setValues(f.getValues());
48095 this.items.each(function(f){
48096 if (!f.getName()) {
48099 var v = f.getValue();
48100 if (f.inputType =='radio') {
48101 if (typeof(ret[f.getName()]) == 'undefined') {
48102 ret[f.getName()] = ''; // empty..
48105 if (!f.el.dom.checked) {
48109 v = f.el.dom.value;
48113 // not sure if this supported any more..
48114 if ((typeof(v) == 'object') && f.getRawValue) {
48115 v = f.getRawValue() ; // dates..
48117 // combo boxes where name != hiddenName...
48118 if (f.name != f.getName()) {
48119 ret[f.name] = f.getRawValue();
48121 ret[f.getName()] = v;
48128 * Clears all invalid messages in this form.
48129 * @return {BasicForm} this
48131 clearInvalid : function(){
48132 this.items.each(function(f){
48136 Roo.each(this.childForms || [], function (f) {
48145 * Resets this form.
48146 * @return {BasicForm} this
48148 reset : function(){
48149 this.items.each(function(f){
48153 Roo.each(this.childForms || [], function (f) {
48156 this.resetHasChanged();
48162 * Add Roo.form components to this form.
48163 * @param {Field} field1
48164 * @param {Field} field2 (optional)
48165 * @param {Field} etc (optional)
48166 * @return {BasicForm} this
48169 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48175 * Removes a field from the items collection (does NOT remove its markup).
48176 * @param {Field} field
48177 * @return {BasicForm} this
48179 remove : function(field){
48180 this.items.remove(field);
48185 * Looks at the fields in this form, checks them for an id attribute,
48186 * and calls applyTo on the existing dom element with that id.
48187 * @return {BasicForm} this
48189 render : function(){
48190 this.items.each(function(f){
48191 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48199 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48200 * @param {Object} values
48201 * @return {BasicForm} this
48203 applyToFields : function(o){
48204 this.items.each(function(f){
48211 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48212 * @param {Object} values
48213 * @return {BasicForm} this
48215 applyIfToFields : function(o){
48216 this.items.each(function(f){
48224 Roo.BasicForm = Roo.form.BasicForm;
48226 Roo.apply(Roo.form.BasicForm, {
48240 intervalID : false,
48246 if(this.isApplied){
48251 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48252 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48253 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48254 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48257 this.maskEl.top.enableDisplayMode("block");
48258 this.maskEl.left.enableDisplayMode("block");
48259 this.maskEl.bottom.enableDisplayMode("block");
48260 this.maskEl.right.enableDisplayMode("block");
48262 Roo.get(document.body).on('click', function(){
48266 Roo.get(document.body).on('touchstart', function(){
48270 this.isApplied = true
48273 mask : function(form, target)
48277 this.target = target;
48279 if(!this.form.errorMask || !target.el){
48283 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48285 var ot = this.target.el.calcOffsetsTo(scrollable);
48287 var scrollTo = ot[1] - this.form.maskOffset;
48289 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48291 scrollable.scrollTo('top', scrollTo);
48293 var el = this.target.wrap || this.target.el;
48295 var box = el.getBox();
48297 this.maskEl.top.setStyle('position', 'absolute');
48298 this.maskEl.top.setStyle('z-index', 10000);
48299 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48300 this.maskEl.top.setLeft(0);
48301 this.maskEl.top.setTop(0);
48302 this.maskEl.top.show();
48304 this.maskEl.left.setStyle('position', 'absolute');
48305 this.maskEl.left.setStyle('z-index', 10000);
48306 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48307 this.maskEl.left.setLeft(0);
48308 this.maskEl.left.setTop(box.y - this.padding);
48309 this.maskEl.left.show();
48311 this.maskEl.bottom.setStyle('position', 'absolute');
48312 this.maskEl.bottom.setStyle('z-index', 10000);
48313 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48314 this.maskEl.bottom.setLeft(0);
48315 this.maskEl.bottom.setTop(box.bottom + this.padding);
48316 this.maskEl.bottom.show();
48318 this.maskEl.right.setStyle('position', 'absolute');
48319 this.maskEl.right.setStyle('z-index', 10000);
48320 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48321 this.maskEl.right.setLeft(box.right + this.padding);
48322 this.maskEl.right.setTop(box.y - this.padding);
48323 this.maskEl.right.show();
48325 this.intervalID = window.setInterval(function() {
48326 Roo.form.BasicForm.popover.unmask();
48329 window.onwheel = function(){ return false;};
48331 (function(){ this.isMasked = true; }).defer(500, this);
48335 unmask : function()
48337 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48341 this.maskEl.top.setStyle('position', 'absolute');
48342 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48343 this.maskEl.top.hide();
48345 this.maskEl.left.setStyle('position', 'absolute');
48346 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48347 this.maskEl.left.hide();
48349 this.maskEl.bottom.setStyle('position', 'absolute');
48350 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48351 this.maskEl.bottom.hide();
48353 this.maskEl.right.setStyle('position', 'absolute');
48354 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48355 this.maskEl.right.hide();
48357 window.onwheel = function(){ return true;};
48359 if(this.intervalID){
48360 window.clearInterval(this.intervalID);
48361 this.intervalID = false;
48364 this.isMasked = false;
48372 * Ext JS Library 1.1.1
48373 * Copyright(c) 2006-2007, Ext JS, LLC.
48375 * Originally Released Under LGPL - original licence link has changed is not relivant.
48378 * <script type="text/javascript">
48382 * @class Roo.form.Form
48383 * @extends Roo.form.BasicForm
48384 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48386 * @param {Object} config Configuration options
48388 Roo.form.Form = function(config){
48390 if (config.items) {
48391 xitems = config.items;
48392 delete config.items;
48396 Roo.form.Form.superclass.constructor.call(this, null, config);
48397 this.url = this.url || this.action;
48399 this.root = new Roo.form.Layout(Roo.applyIf({
48403 this.active = this.root;
48405 * Array of all the buttons that have been added to this form via {@link addButton}
48409 this.allItems = [];
48412 * @event clientvalidation
48413 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48414 * @param {Form} this
48415 * @param {Boolean} valid true if the form has passed client-side validation
48417 clientvalidation: true,
48420 * Fires when the form is rendered
48421 * @param {Roo.form.Form} form
48426 if (this.progressUrl) {
48427 // push a hidden field onto the list of fields..
48431 name : 'UPLOAD_IDENTIFIER'
48436 Roo.each(xitems, this.addxtype, this);
48440 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48442 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48445 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48448 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48450 buttonAlign:'center',
48453 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48458 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48459 * This property cascades to child containers if not set.
48464 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48465 * fires a looping event with that state. This is required to bind buttons to the valid
48466 * state using the config value formBind:true on the button.
48468 monitorValid : false,
48471 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48476 * @cfg {String} progressUrl - Url to return progress data
48479 progressUrl : false,
48481 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48482 * sending a formdata with extra parameters - eg uploaded elements.
48488 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48489 * fields are added and the column is closed. If no fields are passed the column remains open
48490 * until end() is called.
48491 * @param {Object} config The config to pass to the column
48492 * @param {Field} field1 (optional)
48493 * @param {Field} field2 (optional)
48494 * @param {Field} etc (optional)
48495 * @return Column The column container object
48497 column : function(c){
48498 var col = new Roo.form.Column(c);
48500 if(arguments.length > 1){ // duplicate code required because of Opera
48501 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48508 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48509 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48510 * until end() is called.
48511 * @param {Object} config The config to pass to the fieldset
48512 * @param {Field} field1 (optional)
48513 * @param {Field} field2 (optional)
48514 * @param {Field} etc (optional)
48515 * @return FieldSet The fieldset container object
48517 fieldset : function(c){
48518 var fs = new Roo.form.FieldSet(c);
48520 if(arguments.length > 1){ // duplicate code required because of Opera
48521 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48528 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48529 * fields are added and the container is closed. If no fields are passed the container remains open
48530 * until end() is called.
48531 * @param {Object} config The config to pass to the Layout
48532 * @param {Field} field1 (optional)
48533 * @param {Field} field2 (optional)
48534 * @param {Field} etc (optional)
48535 * @return Layout The container object
48537 container : function(c){
48538 var l = new Roo.form.Layout(c);
48540 if(arguments.length > 1){ // duplicate code required because of Opera
48541 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48548 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48549 * @param {Object} container A Roo.form.Layout or subclass of Layout
48550 * @return {Form} this
48552 start : function(c){
48553 // cascade label info
48554 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48555 this.active.stack.push(c);
48556 c.ownerCt = this.active;
48562 * Closes the current open container
48563 * @return {Form} this
48566 if(this.active == this.root){
48569 this.active = this.active.ownerCt;
48574 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48575 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48576 * as the label of the field.
48577 * @param {Field} field1
48578 * @param {Field} field2 (optional)
48579 * @param {Field} etc. (optional)
48580 * @return {Form} this
48583 this.active.stack.push.apply(this.active.stack, arguments);
48584 this.allItems.push.apply(this.allItems,arguments);
48586 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48587 if(a[i].isFormField){
48592 Roo.form.Form.superclass.add.apply(this, r);
48602 * Find any element that has been added to a form, using it's ID or name
48603 * This can include framesets, columns etc. along with regular fields..
48604 * @param {String} id - id or name to find.
48606 * @return {Element} e - or false if nothing found.
48608 findbyId : function(id)
48614 Roo.each(this.allItems, function(f){
48615 if (f.id == id || f.name == id ){
48626 * Render this form into the passed container. This should only be called once!
48627 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48628 * @return {Form} this
48630 render : function(ct)
48636 var o = this.autoCreate || {
48638 method : this.method || 'POST',
48639 id : this.id || Roo.id()
48641 this.initEl(ct.createChild(o));
48643 this.root.render(this.el);
48647 this.items.each(function(f){
48648 f.render('x-form-el-'+f.id);
48651 if(this.buttons.length > 0){
48652 // tables are required to maintain order and for correct IE layout
48653 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48654 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48655 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48657 var tr = tb.getElementsByTagName('tr')[0];
48658 for(var i = 0, len = this.buttons.length; i < len; i++) {
48659 var b = this.buttons[i];
48660 var td = document.createElement('td');
48661 td.className = 'x-form-btn-td';
48662 b.render(tr.appendChild(td));
48665 if(this.monitorValid){ // initialize after render
48666 this.startMonitoring();
48668 this.fireEvent('rendered', this);
48673 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48674 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48675 * object or a valid Roo.DomHelper element config
48676 * @param {Function} handler The function called when the button is clicked
48677 * @param {Object} scope (optional) The scope of the handler function
48678 * @return {Roo.Button}
48680 addButton : function(config, handler, scope){
48684 minWidth: this.minButtonWidth,
48687 if(typeof config == "string"){
48690 Roo.apply(bc, config);
48692 var btn = new Roo.Button(null, bc);
48693 this.buttons.push(btn);
48698 * Adds a series of form elements (using the xtype property as the factory method.
48699 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48700 * @param {Object} config
48703 addxtype : function()
48705 var ar = Array.prototype.slice.call(arguments, 0);
48707 for(var i = 0; i < ar.length; i++) {
48709 continue; // skip -- if this happends something invalid got sent, we
48710 // should ignore it, as basically that interface element will not show up
48711 // and that should be pretty obvious!!
48714 if (Roo.form[ar[i].xtype]) {
48716 var fe = Roo.factory(ar[i], Roo.form);
48722 fe.store.form = this;
48727 this.allItems.push(fe);
48728 if (fe.items && fe.addxtype) {
48729 fe.addxtype.apply(fe, fe.items);
48739 // console.log('adding ' + ar[i].xtype);
48741 if (ar[i].xtype == 'Button') {
48742 //console.log('adding button');
48743 //console.log(ar[i]);
48744 this.addButton(ar[i]);
48745 this.allItems.push(fe);
48749 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48750 alert('end is not supported on xtype any more, use items');
48752 // //console.log('adding end');
48760 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48761 * option "monitorValid"
48763 startMonitoring : function(){
48766 Roo.TaskMgr.start({
48767 run : this.bindHandler,
48768 interval : this.monitorPoll || 200,
48775 * Stops monitoring of the valid state of this form
48777 stopMonitoring : function(){
48778 this.bound = false;
48782 bindHandler : function(){
48784 return false; // stops binding
48787 this.items.each(function(f){
48788 if(!f.isValid(true)){
48793 for(var i = 0, len = this.buttons.length; i < len; i++){
48794 var btn = this.buttons[i];
48795 if(btn.formBind === true && btn.disabled === valid){
48796 btn.setDisabled(!valid);
48799 this.fireEvent('clientvalidation', this, valid);
48813 Roo.Form = Roo.form.Form;
48816 * Ext JS Library 1.1.1
48817 * Copyright(c) 2006-2007, Ext JS, LLC.
48819 * Originally Released Under LGPL - original licence link has changed is not relivant.
48822 * <script type="text/javascript">
48825 // as we use this in bootstrap.
48826 Roo.namespace('Roo.form');
48828 * @class Roo.form.Action
48829 * Internal Class used to handle form actions
48831 * @param {Roo.form.BasicForm} el The form element or its id
48832 * @param {Object} config Configuration options
48837 // define the action interface
48838 Roo.form.Action = function(form, options){
48840 this.options = options || {};
48843 * Client Validation Failed
48846 Roo.form.Action.CLIENT_INVALID = 'client';
48848 * Server Validation Failed
48851 Roo.form.Action.SERVER_INVALID = 'server';
48853 * Connect to Server Failed
48856 Roo.form.Action.CONNECT_FAILURE = 'connect';
48858 * Reading Data from Server Failed
48861 Roo.form.Action.LOAD_FAILURE = 'load';
48863 Roo.form.Action.prototype = {
48865 failureType : undefined,
48866 response : undefined,
48867 result : undefined,
48869 // interface method
48870 run : function(options){
48874 // interface method
48875 success : function(response){
48879 // interface method
48880 handleResponse : function(response){
48884 // default connection failure
48885 failure : function(response){
48887 this.response = response;
48888 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48889 this.form.afterAction(this, false);
48892 processResponse : function(response){
48893 this.response = response;
48894 if(!response.responseText){
48897 this.result = this.handleResponse(response);
48898 return this.result;
48901 // utility functions used internally
48902 getUrl : function(appendParams){
48903 var url = this.options.url || this.form.url || this.form.el.dom.action;
48905 var p = this.getParams();
48907 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
48913 getMethod : function(){
48914 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
48917 getParams : function(){
48918 var bp = this.form.baseParams;
48919 var p = this.options.params;
48921 if(typeof p == "object"){
48922 p = Roo.urlEncode(Roo.applyIf(p, bp));
48923 }else if(typeof p == 'string' && bp){
48924 p += '&' + Roo.urlEncode(bp);
48927 p = Roo.urlEncode(bp);
48932 createCallback : function(){
48934 success: this.success,
48935 failure: this.failure,
48937 timeout: (this.form.timeout*1000),
48938 upload: this.form.fileUpload ? this.success : undefined
48943 Roo.form.Action.Submit = function(form, options){
48944 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
48947 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
48950 haveProgress : false,
48951 uploadComplete : false,
48953 // uploadProgress indicator.
48954 uploadProgress : function()
48956 if (!this.form.progressUrl) {
48960 if (!this.haveProgress) {
48961 Roo.MessageBox.progress("Uploading", "Uploading");
48963 if (this.uploadComplete) {
48964 Roo.MessageBox.hide();
48968 this.haveProgress = true;
48970 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
48972 var c = new Roo.data.Connection();
48974 url : this.form.progressUrl,
48979 success : function(req){
48980 //console.log(data);
48984 rdata = Roo.decode(req.responseText)
48986 Roo.log("Invalid data from server..");
48990 if (!rdata || !rdata.success) {
48992 Roo.MessageBox.alert(Roo.encode(rdata));
48995 var data = rdata.data;
48997 if (this.uploadComplete) {
48998 Roo.MessageBox.hide();
49003 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
49004 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
49007 this.uploadProgress.defer(2000,this);
49010 failure: function(data) {
49011 Roo.log('progress url failed ');
49022 // run get Values on the form, so it syncs any secondary forms.
49023 this.form.getValues();
49025 var o = this.options;
49026 var method = this.getMethod();
49027 var isPost = method == 'POST';
49028 if(o.clientValidation === false || this.form.isValid()){
49030 if (this.form.progressUrl) {
49031 this.form.findField('UPLOAD_IDENTIFIER').setValue(
49032 (new Date() * 1) + '' + Math.random());
49037 Roo.Ajax.request(Roo.apply(this.createCallback(), {
49038 form:this.form.el.dom,
49039 url:this.getUrl(!isPost),
49041 params:isPost ? this.getParams() : null,
49042 isUpload: this.form.fileUpload,
49043 formData : this.form.formData
49046 this.uploadProgress();
49048 }else if (o.clientValidation !== false){ // client validation failed
49049 this.failureType = Roo.form.Action.CLIENT_INVALID;
49050 this.form.afterAction(this, false);
49054 success : function(response)
49056 this.uploadComplete= true;
49057 if (this.haveProgress) {
49058 Roo.MessageBox.hide();
49062 var result = this.processResponse(response);
49063 if(result === true || result.success){
49064 this.form.afterAction(this, true);
49068 this.form.markInvalid(result.errors);
49069 this.failureType = Roo.form.Action.SERVER_INVALID;
49071 this.form.afterAction(this, false);
49073 failure : function(response)
49075 this.uploadComplete= true;
49076 if (this.haveProgress) {
49077 Roo.MessageBox.hide();
49080 this.response = response;
49081 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49082 this.form.afterAction(this, false);
49085 handleResponse : function(response){
49086 if(this.form.errorReader){
49087 var rs = this.form.errorReader.read(response);
49090 for(var i = 0, len = rs.records.length; i < len; i++) {
49091 var r = rs.records[i];
49092 errors[i] = r.data;
49095 if(errors.length < 1){
49099 success : rs.success,
49105 ret = Roo.decode(response.responseText);
49109 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49119 Roo.form.Action.Load = function(form, options){
49120 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49121 this.reader = this.form.reader;
49124 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49129 Roo.Ajax.request(Roo.apply(
49130 this.createCallback(), {
49131 method:this.getMethod(),
49132 url:this.getUrl(false),
49133 params:this.getParams()
49137 success : function(response){
49139 var result = this.processResponse(response);
49140 if(result === true || !result.success || !result.data){
49141 this.failureType = Roo.form.Action.LOAD_FAILURE;
49142 this.form.afterAction(this, false);
49145 this.form.clearInvalid();
49146 this.form.setValues(result.data);
49147 this.form.afterAction(this, true);
49150 handleResponse : function(response){
49151 if(this.form.reader){
49152 var rs = this.form.reader.read(response);
49153 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49155 success : rs.success,
49159 return Roo.decode(response.responseText);
49163 Roo.form.Action.ACTION_TYPES = {
49164 'load' : Roo.form.Action.Load,
49165 'submit' : Roo.form.Action.Submit
49168 * Ext JS Library 1.1.1
49169 * Copyright(c) 2006-2007, Ext JS, LLC.
49171 * Originally Released Under LGPL - original licence link has changed is not relivant.
49174 * <script type="text/javascript">
49178 * @class Roo.form.Layout
49179 * @extends Roo.Component
49180 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49182 * @param {Object} config Configuration options
49184 Roo.form.Layout = function(config){
49186 if (config.items) {
49187 xitems = config.items;
49188 delete config.items;
49190 Roo.form.Layout.superclass.constructor.call(this, config);
49192 Roo.each(xitems, this.addxtype, this);
49196 Roo.extend(Roo.form.Layout, Roo.Component, {
49198 * @cfg {String/Object} autoCreate
49199 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49202 * @cfg {String/Object/Function} style
49203 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49204 * a function which returns such a specification.
49207 * @cfg {String} labelAlign
49208 * Valid values are "left," "top" and "right" (defaults to "left")
49211 * @cfg {Number} labelWidth
49212 * Fixed width in pixels of all field labels (defaults to undefined)
49215 * @cfg {Boolean} clear
49216 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49220 * @cfg {String} labelSeparator
49221 * The separator to use after field labels (defaults to ':')
49223 labelSeparator : ':',
49225 * @cfg {Boolean} hideLabels
49226 * True to suppress the display of field labels in this layout (defaults to false)
49228 hideLabels : false,
49231 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49236 onRender : function(ct, position){
49237 if(this.el){ // from markup
49238 this.el = Roo.get(this.el);
49239 }else { // generate
49240 var cfg = this.getAutoCreate();
49241 this.el = ct.createChild(cfg, position);
49244 this.el.applyStyles(this.style);
49246 if(this.labelAlign){
49247 this.el.addClass('x-form-label-'+this.labelAlign);
49249 if(this.hideLabels){
49250 this.labelStyle = "display:none";
49251 this.elementStyle = "padding-left:0;";
49253 if(typeof this.labelWidth == 'number'){
49254 this.labelStyle = "width:"+this.labelWidth+"px;";
49255 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49257 if(this.labelAlign == 'top'){
49258 this.labelStyle = "width:auto;";
49259 this.elementStyle = "padding-left:0;";
49262 var stack = this.stack;
49263 var slen = stack.length;
49265 if(!this.fieldTpl){
49266 var t = new Roo.Template(
49267 '<div class="x-form-item {5}">',
49268 '<label for="{0}" style="{2}">{1}{4}</label>',
49269 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49271 '</div><div class="x-form-clear-left"></div>'
49273 t.disableFormats = true;
49275 Roo.form.Layout.prototype.fieldTpl = t;
49277 for(var i = 0; i < slen; i++) {
49278 if(stack[i].isFormField){
49279 this.renderField(stack[i]);
49281 this.renderComponent(stack[i]);
49286 this.el.createChild({cls:'x-form-clear'});
49291 renderField : function(f){
49292 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49295 f.labelStyle||this.labelStyle||'', //2
49296 this.elementStyle||'', //3
49297 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49298 f.itemCls||this.itemCls||'' //5
49299 ], true).getPrevSibling());
49303 renderComponent : function(c){
49304 c.render(c.isLayout ? this.el : this.el.createChild());
49307 * Adds a object form elements (using the xtype property as the factory method.)
49308 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49309 * @param {Object} config
49311 addxtype : function(o)
49313 // create the lement.
49314 o.form = this.form;
49315 var fe = Roo.factory(o, Roo.form);
49316 this.form.allItems.push(fe);
49317 this.stack.push(fe);
49319 if (fe.isFormField) {
49320 this.form.items.add(fe);
49328 * @class Roo.form.Column
49329 * @extends Roo.form.Layout
49330 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49332 * @param {Object} config Configuration options
49334 Roo.form.Column = function(config){
49335 Roo.form.Column.superclass.constructor.call(this, config);
49338 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49340 * @cfg {Number/String} width
49341 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49344 * @cfg {String/Object} autoCreate
49345 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49349 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49352 onRender : function(ct, position){
49353 Roo.form.Column.superclass.onRender.call(this, ct, position);
49355 this.el.setWidth(this.width);
49362 * @class Roo.form.Row
49363 * @extends Roo.form.Layout
49364 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49366 * @param {Object} config Configuration options
49370 Roo.form.Row = function(config){
49371 Roo.form.Row.superclass.constructor.call(this, config);
49374 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49376 * @cfg {Number/String} width
49377 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49380 * @cfg {Number/String} height
49381 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49383 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49387 onRender : function(ct, position){
49388 //console.log('row render');
49390 var t = new Roo.Template(
49391 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49392 '<label for="{0}" style="{2}">{1}{4}</label>',
49393 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49397 t.disableFormats = true;
49399 Roo.form.Layout.prototype.rowTpl = t;
49401 this.fieldTpl = this.rowTpl;
49403 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49404 var labelWidth = 100;
49406 if ((this.labelAlign != 'top')) {
49407 if (typeof this.labelWidth == 'number') {
49408 labelWidth = this.labelWidth
49410 this.padWidth = 20 + labelWidth;
49414 Roo.form.Column.superclass.onRender.call(this, ct, position);
49416 this.el.setWidth(this.width);
49419 this.el.setHeight(this.height);
49424 renderField : function(f){
49425 f.fieldEl = this.fieldTpl.append(this.el, [
49426 f.id, f.fieldLabel,
49427 f.labelStyle||this.labelStyle||'',
49428 this.elementStyle||'',
49429 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49430 f.itemCls||this.itemCls||'',
49431 f.width ? f.width + this.padWidth : 160 + this.padWidth
49438 * @class Roo.form.FieldSet
49439 * @extends Roo.form.Layout
49440 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49442 * @param {Object} config Configuration options
49444 Roo.form.FieldSet = function(config){
49445 Roo.form.FieldSet.superclass.constructor.call(this, config);
49448 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49450 * @cfg {String} legend
49451 * The text to display as the legend for the FieldSet (defaults to '')
49454 * @cfg {String/Object} autoCreate
49455 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49459 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49462 onRender : function(ct, position){
49463 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49465 this.setLegend(this.legend);
49470 setLegend : function(text){
49472 this.el.child('legend').update(text);
49477 * Ext JS Library 1.1.1
49478 * Copyright(c) 2006-2007, Ext JS, LLC.
49480 * Originally Released Under LGPL - original licence link has changed is not relivant.
49483 * <script type="text/javascript">
49486 * @class Roo.form.VTypes
49487 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49490 Roo.form.VTypes = function(){
49491 // closure these in so they are only created once.
49492 var alpha = /^[a-zA-Z_]+$/;
49493 var alphanum = /^[a-zA-Z0-9_]+$/;
49494 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49495 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49497 // All these messages and functions are configurable
49500 * The function used to validate email addresses
49501 * @param {String} value The email address
49503 'email' : function(v){
49504 return email.test(v);
49507 * The error text to display when the email validation function returns false
49510 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49512 * The keystroke filter mask to be applied on email input
49515 'emailMask' : /[a-z0-9_\.\-@]/i,
49518 * The function used to validate URLs
49519 * @param {String} value The URL
49521 'url' : function(v){
49522 return url.test(v);
49525 * The error text to display when the url validation function returns false
49528 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49531 * The function used to validate alpha values
49532 * @param {String} value The value
49534 'alpha' : function(v){
49535 return alpha.test(v);
49538 * The error text to display when the alpha validation function returns false
49541 'alphaText' : 'This field should only contain letters and _',
49543 * The keystroke filter mask to be applied on alpha input
49546 'alphaMask' : /[a-z_]/i,
49549 * The function used to validate alphanumeric values
49550 * @param {String} value The value
49552 'alphanum' : function(v){
49553 return alphanum.test(v);
49556 * The error text to display when the alphanumeric validation function returns false
49559 'alphanumText' : 'This field should only contain letters, numbers and _',
49561 * The keystroke filter mask to be applied on alphanumeric input
49564 'alphanumMask' : /[a-z0-9_]/i
49566 }();//<script type="text/javascript">
49569 * @class Roo.form.FCKeditor
49570 * @extends Roo.form.TextArea
49571 * Wrapper around the FCKEditor http://www.fckeditor.net
49573 * Creates a new FCKeditor
49574 * @param {Object} config Configuration options
49576 Roo.form.FCKeditor = function(config){
49577 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49580 * @event editorinit
49581 * Fired when the editor is initialized - you can add extra handlers here..
49582 * @param {FCKeditor} this
49583 * @param {Object} the FCK object.
49590 Roo.form.FCKeditor.editors = { };
49591 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49593 //defaultAutoCreate : {
49594 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49598 * @cfg {Object} fck options - see fck manual for details.
49603 * @cfg {Object} fck toolbar set (Basic or Default)
49605 toolbarSet : 'Basic',
49607 * @cfg {Object} fck BasePath
49609 basePath : '/fckeditor/',
49617 onRender : function(ct, position)
49620 this.defaultAutoCreate = {
49622 style:"width:300px;height:60px;",
49623 autocomplete: "new-password"
49626 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49629 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49630 if(this.preventScrollbars){
49631 this.el.setStyle("overflow", "hidden");
49633 this.el.setHeight(this.growMin);
49636 //console.log('onrender' + this.getId() );
49637 Roo.form.FCKeditor.editors[this.getId()] = this;
49640 this.replaceTextarea() ;
49644 getEditor : function() {
49645 return this.fckEditor;
49648 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49649 * @param {Mixed} value The value to set
49653 setValue : function(value)
49655 //console.log('setValue: ' + value);
49657 if(typeof(value) == 'undefined') { // not sure why this is happending...
49660 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49662 //if(!this.el || !this.getEditor()) {
49663 // this.value = value;
49664 //this.setValue.defer(100,this,[value]);
49668 if(!this.getEditor()) {
49672 this.getEditor().SetData(value);
49679 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49680 * @return {Mixed} value The field value
49682 getValue : function()
49685 if (this.frame && this.frame.dom.style.display == 'none') {
49686 return Roo.form.FCKeditor.superclass.getValue.call(this);
49689 if(!this.el || !this.getEditor()) {
49691 // this.getValue.defer(100,this);
49696 var value=this.getEditor().GetData();
49697 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49698 return Roo.form.FCKeditor.superclass.getValue.call(this);
49704 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49705 * @return {Mixed} value The field value
49707 getRawValue : function()
49709 if (this.frame && this.frame.dom.style.display == 'none') {
49710 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49713 if(!this.el || !this.getEditor()) {
49714 //this.getRawValue.defer(100,this);
49721 var value=this.getEditor().GetData();
49722 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49723 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49727 setSize : function(w,h) {
49731 //if (this.frame && this.frame.dom.style.display == 'none') {
49732 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49735 //if(!this.el || !this.getEditor()) {
49736 // this.setSize.defer(100,this, [w,h]);
49742 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49744 this.frame.dom.setAttribute('width', w);
49745 this.frame.dom.setAttribute('height', h);
49746 this.frame.setSize(w,h);
49750 toggleSourceEdit : function(value) {
49754 this.el.dom.style.display = value ? '' : 'none';
49755 this.frame.dom.style.display = value ? 'none' : '';
49760 focus: function(tag)
49762 if (this.frame.dom.style.display == 'none') {
49763 return Roo.form.FCKeditor.superclass.focus.call(this);
49765 if(!this.el || !this.getEditor()) {
49766 this.focus.defer(100,this, [tag]);
49773 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49774 this.getEditor().Focus();
49776 if (!this.getEditor().Selection.GetSelection()) {
49777 this.focus.defer(100,this, [tag]);
49782 var r = this.getEditor().EditorDocument.createRange();
49783 r.setStart(tgs[0],0);
49784 r.setEnd(tgs[0],0);
49785 this.getEditor().Selection.GetSelection().removeAllRanges();
49786 this.getEditor().Selection.GetSelection().addRange(r);
49787 this.getEditor().Focus();
49794 replaceTextarea : function()
49796 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49799 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49801 // We must check the elements firstly using the Id and then the name.
49802 var oTextarea = document.getElementById( this.getId() );
49804 var colElementsByName = document.getElementsByName( this.getId() ) ;
49806 oTextarea.style.display = 'none' ;
49808 if ( oTextarea.tabIndex ) {
49809 this.TabIndex = oTextarea.tabIndex ;
49812 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49813 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49814 this.frame = Roo.get(this.getId() + '___Frame')
49817 _getConfigHtml : function()
49821 for ( var o in this.fckconfig ) {
49822 sConfig += sConfig.length > 0 ? '&' : '';
49823 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49826 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49830 _getIFrameHtml : function()
49832 var sFile = 'fckeditor.html' ;
49833 /* no idea what this is about..
49836 if ( (/fcksource=true/i).test( window.top.location.search ) )
49837 sFile = 'fckeditor.original.html' ;
49842 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49843 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49846 var html = '<iframe id="' + this.getId() +
49847 '___Frame" src="' + sLink +
49848 '" width="' + this.width +
49849 '" height="' + this.height + '"' +
49850 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
49851 ' frameborder="0" scrolling="no"></iframe>' ;
49856 _insertHtmlBefore : function( html, element )
49858 if ( element.insertAdjacentHTML ) {
49860 element.insertAdjacentHTML( 'beforeBegin', html ) ;
49862 var oRange = document.createRange() ;
49863 oRange.setStartBefore( element ) ;
49864 var oFragment = oRange.createContextualFragment( html );
49865 element.parentNode.insertBefore( oFragment, element ) ;
49878 //Roo.reg('fckeditor', Roo.form.FCKeditor);
49880 function FCKeditor_OnComplete(editorInstance){
49881 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
49882 f.fckEditor = editorInstance;
49883 //console.log("loaded");
49884 f.fireEvent('editorinit', f, editorInstance);
49904 //<script type="text/javascript">
49906 * @class Roo.form.GridField
49907 * @extends Roo.form.Field
49908 * Embed a grid (or editable grid into a form)
49911 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
49913 * xgrid.store = Roo.data.Store
49914 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
49915 * xgrid.store.reader = Roo.data.JsonReader
49919 * Creates a new GridField
49920 * @param {Object} config Configuration options
49922 Roo.form.GridField = function(config){
49923 Roo.form.GridField.superclass.constructor.call(this, config);
49927 Roo.extend(Roo.form.GridField, Roo.form.Field, {
49929 * @cfg {Number} width - used to restrict width of grid..
49933 * @cfg {Number} height - used to restrict height of grid..
49937 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
49943 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49944 * {tag: "input", type: "checkbox", autocomplete: "off"})
49946 // defaultAutoCreate : { tag: 'div' },
49947 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
49949 * @cfg {String} addTitle Text to include for adding a title.
49953 onResize : function(){
49954 Roo.form.Field.superclass.onResize.apply(this, arguments);
49957 initEvents : function(){
49958 // Roo.form.Checkbox.superclass.initEvents.call(this);
49959 // has no events...
49964 getResizeEl : function(){
49968 getPositionEl : function(){
49973 onRender : function(ct, position){
49975 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
49976 var style = this.style;
49979 Roo.form.GridField.superclass.onRender.call(this, ct, position);
49980 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
49981 this.viewEl = this.wrap.createChild({ tag: 'div' });
49983 this.viewEl.applyStyles(style);
49986 this.viewEl.setWidth(this.width);
49989 this.viewEl.setHeight(this.height);
49991 //if(this.inputValue !== undefined){
49992 //this.setValue(this.value);
49995 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
49998 this.grid.render();
49999 this.grid.getDataSource().on('remove', this.refreshValue, this);
50000 this.grid.getDataSource().on('update', this.refreshValue, this);
50001 this.grid.on('afteredit', this.refreshValue, this);
50007 * Sets the value of the item.
50008 * @param {String} either an object or a string..
50010 setValue : function(v){
50012 v = v || []; // empty set..
50013 // this does not seem smart - it really only affects memoryproxy grids..
50014 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
50015 var ds = this.grid.getDataSource();
50016 // assumes a json reader..
50018 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
50019 ds.loadData( data);
50021 // clear selection so it does not get stale.
50022 if (this.grid.sm) {
50023 this.grid.sm.clearSelections();
50026 Roo.form.GridField.superclass.setValue.call(this, v);
50027 this.refreshValue();
50028 // should load data in the grid really....
50032 refreshValue: function() {
50034 this.grid.getDataSource().each(function(r) {
50037 this.el.dom.value = Roo.encode(val);
50045 * Ext JS Library 1.1.1
50046 * Copyright(c) 2006-2007, Ext JS, LLC.
50048 * Originally Released Under LGPL - original licence link has changed is not relivant.
50051 * <script type="text/javascript">
50054 * @class Roo.form.DisplayField
50055 * @extends Roo.form.Field
50056 * A generic Field to display non-editable data.
50057 * @cfg {Boolean} closable (true|false) default false
50059 * Creates a new Display Field item.
50060 * @param {Object} config Configuration options
50062 Roo.form.DisplayField = function(config){
50063 Roo.form.DisplayField.superclass.constructor.call(this, config);
50068 * Fires after the click the close btn
50069 * @param {Roo.form.DisplayField} this
50075 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50076 inputType: 'hidden',
50082 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50084 focusClass : undefined,
50086 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50088 fieldClass: 'x-form-field',
50091 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50093 valueRenderer: undefined,
50097 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50098 * {tag: "input", type: "checkbox", autocomplete: "off"})
50101 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50105 onResize : function(){
50106 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50110 initEvents : function(){
50111 // Roo.form.Checkbox.superclass.initEvents.call(this);
50112 // has no events...
50115 this.closeEl.on('click', this.onClose, this);
50121 getResizeEl : function(){
50125 getPositionEl : function(){
50130 onRender : function(ct, position){
50132 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50133 //if(this.inputValue !== undefined){
50134 this.wrap = this.el.wrap();
50136 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50139 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50142 if (this.bodyStyle) {
50143 this.viewEl.applyStyles(this.bodyStyle);
50145 //this.viewEl.setStyle('padding', '2px');
50147 this.setValue(this.value);
50152 initValue : Roo.emptyFn,
50157 onClick : function(){
50162 * Sets the checked state of the checkbox.
50163 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50165 setValue : function(v){
50167 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50168 // this might be called before we have a dom element..
50169 if (!this.viewEl) {
50172 this.viewEl.dom.innerHTML = html;
50173 Roo.form.DisplayField.superclass.setValue.call(this, v);
50177 onClose : function(e)
50179 e.preventDefault();
50181 this.fireEvent('close', this);
50190 * @class Roo.form.DayPicker
50191 * @extends Roo.form.Field
50192 * A Day picker show [M] [T] [W] ....
50194 * Creates a new Day Picker
50195 * @param {Object} config Configuration options
50197 Roo.form.DayPicker= function(config){
50198 Roo.form.DayPicker.superclass.constructor.call(this, config);
50202 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50204 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50206 focusClass : undefined,
50208 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50210 fieldClass: "x-form-field",
50213 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50214 * {tag: "input", type: "checkbox", autocomplete: "off"})
50216 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50219 actionMode : 'viewEl',
50223 inputType : 'hidden',
50226 inputElement: false, // real input element?
50227 basedOn: false, // ????
50229 isFormField: true, // not sure where this is needed!!!!
50231 onResize : function(){
50232 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50233 if(!this.boxLabel){
50234 this.el.alignTo(this.wrap, 'c-c');
50238 initEvents : function(){
50239 Roo.form.Checkbox.superclass.initEvents.call(this);
50240 this.el.on("click", this.onClick, this);
50241 this.el.on("change", this.onClick, this);
50245 getResizeEl : function(){
50249 getPositionEl : function(){
50255 onRender : function(ct, position){
50256 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50258 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50260 var r1 = '<table><tr>';
50261 var r2 = '<tr class="x-form-daypick-icons">';
50262 for (var i=0; i < 7; i++) {
50263 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50264 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50267 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50268 viewEl.select('img').on('click', this.onClick, this);
50269 this.viewEl = viewEl;
50272 // this will not work on Chrome!!!
50273 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50274 this.el.on('propertychange', this.setFromHidden, this); //ie
50282 initValue : Roo.emptyFn,
50285 * Returns the checked state of the checkbox.
50286 * @return {Boolean} True if checked, else false
50288 getValue : function(){
50289 return this.el.dom.value;
50294 onClick : function(e){
50295 //this.setChecked(!this.checked);
50296 Roo.get(e.target).toggleClass('x-menu-item-checked');
50297 this.refreshValue();
50298 //if(this.el.dom.checked != this.checked){
50299 // this.setValue(this.el.dom.checked);
50304 refreshValue : function()
50307 this.viewEl.select('img',true).each(function(e,i,n) {
50308 val += e.is(".x-menu-item-checked") ? String(n) : '';
50310 this.setValue(val, true);
50314 * Sets the checked state of the checkbox.
50315 * On is always based on a string comparison between inputValue and the param.
50316 * @param {Boolean/String} value - the value to set
50317 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50319 setValue : function(v,suppressEvent){
50320 if (!this.el.dom) {
50323 var old = this.el.dom.value ;
50324 this.el.dom.value = v;
50325 if (suppressEvent) {
50329 // update display..
50330 this.viewEl.select('img',true).each(function(e,i,n) {
50332 var on = e.is(".x-menu-item-checked");
50333 var newv = v.indexOf(String(n)) > -1;
50335 e.toggleClass('x-menu-item-checked');
50341 this.fireEvent('change', this, v, old);
50346 // handle setting of hidden value by some other method!!?!?
50347 setFromHidden: function()
50352 //console.log("SET FROM HIDDEN");
50353 //alert('setFrom hidden');
50354 this.setValue(this.el.dom.value);
50357 onDestroy : function()
50360 Roo.get(this.viewEl).remove();
50363 Roo.form.DayPicker.superclass.onDestroy.call(this);
50367 * RooJS Library 1.1.1
50368 * Copyright(c) 2008-2011 Alan Knowles
50375 * @class Roo.form.ComboCheck
50376 * @extends Roo.form.ComboBox
50377 * A combobox for multiple select items.
50379 * FIXME - could do with a reset button..
50382 * Create a new ComboCheck
50383 * @param {Object} config Configuration options
50385 Roo.form.ComboCheck = function(config){
50386 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50387 // should verify some data...
50389 // hiddenName = required..
50390 // displayField = required
50391 // valudField == required
50392 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50394 Roo.each(req, function(e) {
50395 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50396 throw "Roo.form.ComboCheck : missing value for: " + e;
50403 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50408 selectedClass: 'x-menu-item-checked',
50411 onRender : function(ct, position){
50417 var cls = 'x-combo-list';
50420 this.tpl = new Roo.Template({
50421 html : '<div class="'+cls+'-item x-menu-check-item">' +
50422 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50423 '<span>{' + this.displayField + '}</span>' +
50430 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50431 this.view.singleSelect = false;
50432 this.view.multiSelect = true;
50433 this.view.toggleSelect = true;
50434 this.pageTb.add(new Roo.Toolbar.Fill(), {
50437 handler: function()
50444 onViewOver : function(e, t){
50450 onViewClick : function(doFocus,index){
50454 select: function () {
50455 //Roo.log("SELECT CALLED");
50458 selectByValue : function(xv, scrollIntoView){
50459 var ar = this.getValueArray();
50462 Roo.each(ar, function(v) {
50463 if(v === undefined || v === null){
50466 var r = this.findRecord(this.valueField, v);
50468 sels.push(this.store.indexOf(r))
50472 this.view.select(sels);
50478 onSelect : function(record, index){
50479 // Roo.log("onselect Called");
50480 // this is only called by the clear button now..
50481 this.view.clearSelections();
50482 this.setValue('[]');
50483 if (this.value != this.valueBefore) {
50484 this.fireEvent('change', this, this.value, this.valueBefore);
50485 this.valueBefore = this.value;
50488 getValueArray : function()
50493 //Roo.log(this.value);
50494 if (typeof(this.value) == 'undefined') {
50497 var ar = Roo.decode(this.value);
50498 return ar instanceof Array ? ar : []; //?? valid?
50501 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50506 expand : function ()
50509 Roo.form.ComboCheck.superclass.expand.call(this);
50510 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50511 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50516 collapse : function(){
50517 Roo.form.ComboCheck.superclass.collapse.call(this);
50518 var sl = this.view.getSelectedIndexes();
50519 var st = this.store;
50523 Roo.each(sl, function(i) {
50525 nv.push(r.get(this.valueField));
50527 this.setValue(Roo.encode(nv));
50528 if (this.value != this.valueBefore) {
50530 this.fireEvent('change', this, this.value, this.valueBefore);
50531 this.valueBefore = this.value;
50536 setValue : function(v){
50540 var vals = this.getValueArray();
50542 Roo.each(vals, function(k) {
50543 var r = this.findRecord(this.valueField, k);
50545 tv.push(r.data[this.displayField]);
50546 }else if(this.valueNotFoundText !== undefined){
50547 tv.push( this.valueNotFoundText );
50552 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50553 this.hiddenField.value = v;
50559 * Ext JS Library 1.1.1
50560 * Copyright(c) 2006-2007, Ext JS, LLC.
50562 * Originally Released Under LGPL - original licence link has changed is not relivant.
50565 * <script type="text/javascript">
50569 * @class Roo.form.Signature
50570 * @extends Roo.form.Field
50574 * @param {Object} config Configuration options
50577 Roo.form.Signature = function(config){
50578 Roo.form.Signature.superclass.constructor.call(this, config);
50580 this.addEvents({// not in used??
50583 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50584 * @param {Roo.form.Signature} combo This combo box
50589 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50590 * @param {Roo.form.ComboBox} combo This combo box
50591 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50597 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50599 * @cfg {Object} labels Label to use when rendering a form.
50603 * confirm : "Confirm"
50608 confirm : "Confirm"
50611 * @cfg {Number} width The signature panel width (defaults to 300)
50615 * @cfg {Number} height The signature panel height (defaults to 100)
50619 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50621 allowBlank : false,
50624 // {Object} signPanel The signature SVG panel element (defaults to {})
50626 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50627 isMouseDown : false,
50628 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50629 isConfirmed : false,
50630 // {String} signatureTmp SVG mapping string (defaults to empty string)
50634 defaultAutoCreate : { // modified by initCompnoent..
50640 onRender : function(ct, position){
50642 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50644 this.wrap = this.el.wrap({
50645 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50648 this.createToolbar(this);
50649 this.signPanel = this.wrap.createChild({
50651 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50655 this.svgID = Roo.id();
50656 this.svgEl = this.signPanel.createChild({
50657 xmlns : 'http://www.w3.org/2000/svg',
50659 id : this.svgID + "-svg",
50661 height: this.height,
50662 viewBox: '0 0 '+this.width+' '+this.height,
50666 id: this.svgID + "-svg-r",
50668 height: this.height,
50673 id: this.svgID + "-svg-l",
50675 y1: (this.height*0.8), // start set the line in 80% of height
50676 x2: this.width, // end
50677 y2: (this.height*0.8), // end set the line in 80% of height
50679 'stroke-width': "1",
50680 'stroke-dasharray': "3",
50681 'shape-rendering': "crispEdges",
50682 'pointer-events': "none"
50686 id: this.svgID + "-svg-p",
50688 'stroke-width': "3",
50690 'pointer-events': 'none'
50695 this.svgBox = this.svgEl.dom.getScreenCTM();
50697 createSVG : function(){
50698 var svg = this.signPanel;
50699 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50702 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50703 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50704 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50705 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50706 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50707 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50708 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50711 isTouchEvent : function(e){
50712 return e.type.match(/^touch/);
50714 getCoords : function (e) {
50715 var pt = this.svgEl.dom.createSVGPoint();
50718 if (this.isTouchEvent(e)) {
50719 pt.x = e.targetTouches[0].clientX;
50720 pt.y = e.targetTouches[0].clientY;
50722 var a = this.svgEl.dom.getScreenCTM();
50723 var b = a.inverse();
50724 var mx = pt.matrixTransform(b);
50725 return mx.x + ',' + mx.y;
50727 //mouse event headler
50728 down : function (e) {
50729 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50730 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50732 this.isMouseDown = true;
50734 e.preventDefault();
50736 move : function (e) {
50737 if (this.isMouseDown) {
50738 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50739 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50742 e.preventDefault();
50744 up : function (e) {
50745 this.isMouseDown = false;
50746 var sp = this.signatureTmp.split(' ');
50749 if(!sp[sp.length-2].match(/^L/)){
50753 this.signatureTmp = sp.join(" ");
50756 if(this.getValue() != this.signatureTmp){
50757 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50758 this.isConfirmed = false;
50760 e.preventDefault();
50764 * Protected method that will not generally be called directly. It
50765 * is called when the editor creates its toolbar. Override this method if you need to
50766 * add custom toolbar buttons.
50767 * @param {HtmlEditor} editor
50769 createToolbar : function(editor){
50770 function btn(id, toggle, handler){
50771 var xid = fid + '-'+ id ;
50775 cls : 'x-btn-icon x-edit-'+id,
50776 enableToggle:toggle !== false,
50777 scope: editor, // was editor...
50778 handler:handler||editor.relayBtnCmd,
50779 clickEvent:'mousedown',
50780 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50786 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50790 cls : ' x-signature-btn x-signature-'+id,
50791 scope: editor, // was editor...
50792 handler: this.reset,
50793 clickEvent:'mousedown',
50794 text: this.labels.clear
50801 cls : ' x-signature-btn x-signature-'+id,
50802 scope: editor, // was editor...
50803 handler: this.confirmHandler,
50804 clickEvent:'mousedown',
50805 text: this.labels.confirm
50812 * when user is clicked confirm then show this image.....
50814 * @return {String} Image Data URI
50816 getImageDataURI : function(){
50817 var svg = this.svgEl.dom.parentNode.innerHTML;
50818 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50823 * @return {Boolean} this.isConfirmed
50825 getConfirmed : function(){
50826 return this.isConfirmed;
50830 * @return {Number} this.width
50832 getWidth : function(){
50837 * @return {Number} this.height
50839 getHeight : function(){
50840 return this.height;
50843 getSignature : function(){
50844 return this.signatureTmp;
50847 reset : function(){
50848 this.signatureTmp = '';
50849 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50850 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
50851 this.isConfirmed = false;
50852 Roo.form.Signature.superclass.reset.call(this);
50854 setSignature : function(s){
50855 this.signatureTmp = s;
50856 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50857 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
50859 this.isConfirmed = false;
50860 Roo.form.Signature.superclass.reset.call(this);
50863 // Roo.log(this.signPanel.dom.contentWindow.up())
50866 setConfirmed : function(){
50870 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
50873 confirmHandler : function(){
50874 if(!this.getSignature()){
50878 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
50879 this.setValue(this.getSignature());
50880 this.isConfirmed = true;
50882 this.fireEvent('confirm', this);
50885 // Subclasses should provide the validation implementation by overriding this
50886 validateValue : function(value){
50887 if(this.allowBlank){
50891 if(this.isConfirmed){
50898 * Ext JS Library 1.1.1
50899 * Copyright(c) 2006-2007, Ext JS, LLC.
50901 * Originally Released Under LGPL - original licence link has changed is not relivant.
50904 * <script type="text/javascript">
50909 * @class Roo.form.ComboBox
50910 * @extends Roo.form.TriggerField
50911 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
50913 * Create a new ComboBox.
50914 * @param {Object} config Configuration options
50916 Roo.form.Select = function(config){
50917 Roo.form.Select.superclass.constructor.call(this, config);
50921 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
50923 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
50926 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
50927 * rendering into an Roo.Editor, defaults to false)
50930 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
50931 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
50934 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
50937 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
50938 * the dropdown list (defaults to undefined, with no header element)
50942 * @cfg {String/Roo.Template} tpl The template to use to render the output
50946 defaultAutoCreate : {tag: "select" },
50948 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
50950 listWidth: undefined,
50952 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
50953 * mode = 'remote' or 'text' if mode = 'local')
50955 displayField: undefined,
50957 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
50958 * mode = 'remote' or 'value' if mode = 'local').
50959 * Note: use of a valueField requires the user make a selection
50960 * in order for a value to be mapped.
50962 valueField: undefined,
50966 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
50967 * field's data value (defaults to the underlying DOM element's name)
50969 hiddenName: undefined,
50971 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
50975 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
50977 selectedClass: 'x-combo-selected',
50979 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
50980 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
50981 * which displays a downward arrow icon).
50983 triggerClass : 'x-form-arrow-trigger',
50985 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
50989 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
50990 * anchor positions (defaults to 'tl-bl')
50992 listAlign: 'tl-bl?',
50994 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
50998 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
50999 * query specified by the allQuery config option (defaults to 'query')
51001 triggerAction: 'query',
51003 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
51004 * (defaults to 4, does not apply if editable = false)
51008 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
51009 * delay (typeAheadDelay) if it matches a known value (defaults to false)
51013 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
51014 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
51018 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
51019 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
51023 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
51024 * when editable = true (defaults to false)
51026 selectOnFocus:false,
51028 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
51030 queryParam: 'query',
51032 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
51033 * when mode = 'remote' (defaults to 'Loading...')
51035 loadingText: 'Loading...',
51037 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
51041 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
51045 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
51046 * traditional select (defaults to true)
51050 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
51054 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
51058 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
51059 * listWidth has a higher value)
51063 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
51064 * allow the user to set arbitrary text into the field (defaults to false)
51066 forceSelection:false,
51068 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
51069 * if typeAhead = true (defaults to 250)
51071 typeAheadDelay : 250,
51073 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
51074 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51076 valueNotFoundText : undefined,
51079 * @cfg {String} defaultValue The value displayed after loading the store.
51084 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51086 blockFocus : false,
51089 * @cfg {Boolean} disableClear Disable showing of clear button.
51091 disableClear : false,
51093 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51095 alwaysQuery : false,
51101 // element that contains real text value.. (when hidden is used..)
51104 onRender : function(ct, position){
51105 Roo.form.Field.prototype.onRender.call(this, ct, position);
51108 this.store.on('beforeload', this.onBeforeLoad, this);
51109 this.store.on('load', this.onLoad, this);
51110 this.store.on('loadexception', this.onLoadException, this);
51111 this.store.load({});
51119 initEvents : function(){
51120 //Roo.form.ComboBox.superclass.initEvents.call(this);
51124 onDestroy : function(){
51127 this.store.un('beforeload', this.onBeforeLoad, this);
51128 this.store.un('load', this.onLoad, this);
51129 this.store.un('loadexception', this.onLoadException, this);
51131 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51135 fireKey : function(e){
51136 if(e.isNavKeyPress() && !this.list.isVisible()){
51137 this.fireEvent("specialkey", this, e);
51142 onResize: function(w, h){
51150 * Allow or prevent the user from directly editing the field text. If false is passed,
51151 * the user will only be able to select from the items defined in the dropdown list. This method
51152 * is the runtime equivalent of setting the 'editable' config option at config time.
51153 * @param {Boolean} value True to allow the user to directly edit the field text
51155 setEditable : function(value){
51160 onBeforeLoad : function(){
51162 Roo.log("Select before load");
51165 this.innerList.update(this.loadingText ?
51166 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51167 //this.restrictHeight();
51168 this.selectedIndex = -1;
51172 onLoad : function(){
51175 var dom = this.el.dom;
51176 dom.innerHTML = '';
51177 var od = dom.ownerDocument;
51179 if (this.emptyText) {
51180 var op = od.createElement('option');
51181 op.setAttribute('value', '');
51182 op.innerHTML = String.format('{0}', this.emptyText);
51183 dom.appendChild(op);
51185 if(this.store.getCount() > 0){
51187 var vf = this.valueField;
51188 var df = this.displayField;
51189 this.store.data.each(function(r) {
51190 // which colmsn to use... testing - cdoe / title..
51191 var op = od.createElement('option');
51192 op.setAttribute('value', r.data[vf]);
51193 op.innerHTML = String.format('{0}', r.data[df]);
51194 dom.appendChild(op);
51196 if (typeof(this.defaultValue != 'undefined')) {
51197 this.setValue(this.defaultValue);
51202 //this.onEmptyResults();
51207 onLoadException : function()
51209 dom.innerHTML = '';
51211 Roo.log("Select on load exception");
51215 Roo.log(this.store.reader.jsonData);
51216 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51217 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51223 onTypeAhead : function(){
51228 onSelect : function(record, index){
51229 Roo.log('on select?');
51231 if(this.fireEvent('beforeselect', this, record, index) !== false){
51232 this.setFromData(index > -1 ? record.data : false);
51234 this.fireEvent('select', this, record, index);
51239 * Returns the currently selected field value or empty string if no value is set.
51240 * @return {String} value The selected value
51242 getValue : function(){
51243 var dom = this.el.dom;
51244 this.value = dom.options[dom.selectedIndex].value;
51250 * Clears any text/value currently set in the field
51252 clearValue : function(){
51254 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51259 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51260 * will be displayed in the field. If the value does not match the data value of an existing item,
51261 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51262 * Otherwise the field will be blank (although the value will still be set).
51263 * @param {String} value The value to match
51265 setValue : function(v){
51266 var d = this.el.dom;
51267 for (var i =0; i < d.options.length;i++) {
51268 if (v == d.options[i].value) {
51269 d.selectedIndex = i;
51277 * @property {Object} the last set data for the element
51282 * Sets the value of the field based on a object which is related to the record format for the store.
51283 * @param {Object} value the value to set as. or false on reset?
51285 setFromData : function(o){
51286 Roo.log('setfrom data?');
51292 reset : function(){
51296 findRecord : function(prop, value){
51301 if(this.store.getCount() > 0){
51302 this.store.each(function(r){
51303 if(r.data[prop] == value){
51313 getName: function()
51315 // returns hidden if it's set..
51316 if (!this.rendered) {return ''};
51317 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51325 onEmptyResults : function(){
51326 Roo.log('empty results');
51331 * Returns true if the dropdown list is expanded, else false.
51333 isExpanded : function(){
51338 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51339 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51340 * @param {String} value The data value of the item to select
51341 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51342 * selected item if it is not currently in view (defaults to true)
51343 * @return {Boolean} True if the value matched an item in the list, else false
51345 selectByValue : function(v, scrollIntoView){
51346 Roo.log('select By Value');
51349 if(v !== undefined && v !== null){
51350 var r = this.findRecord(this.valueField || this.displayField, v);
51352 this.select(this.store.indexOf(r), scrollIntoView);
51360 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51361 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51362 * @param {Number} index The zero-based index of the list item to select
51363 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51364 * selected item if it is not currently in view (defaults to true)
51366 select : function(index, scrollIntoView){
51367 Roo.log('select ');
51370 this.selectedIndex = index;
51371 this.view.select(index);
51372 if(scrollIntoView !== false){
51373 var el = this.view.getNode(index);
51375 this.innerList.scrollChildIntoView(el, false);
51383 validateBlur : function(){
51390 initQuery : function(){
51391 this.doQuery(this.getRawValue());
51395 doForce : function(){
51396 if(this.el.dom.value.length > 0){
51397 this.el.dom.value =
51398 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51404 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51405 * query allowing the query action to be canceled if needed.
51406 * @param {String} query The SQL query to execute
51407 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51408 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51409 * saved in the current store (defaults to false)
51411 doQuery : function(q, forceAll){
51413 Roo.log('doQuery?');
51414 if(q === undefined || q === null){
51419 forceAll: forceAll,
51423 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51427 forceAll = qe.forceAll;
51428 if(forceAll === true || (q.length >= this.minChars)){
51429 if(this.lastQuery != q || this.alwaysQuery){
51430 this.lastQuery = q;
51431 if(this.mode == 'local'){
51432 this.selectedIndex = -1;
51434 this.store.clearFilter();
51436 this.store.filter(this.displayField, q);
51440 this.store.baseParams[this.queryParam] = q;
51442 params: this.getParams(q)
51447 this.selectedIndex = -1;
51454 getParams : function(q){
51456 //p[this.queryParam] = q;
51459 p.limit = this.pageSize;
51465 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51467 collapse : function(){
51472 collapseIf : function(e){
51477 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51479 expand : function(){
51487 * @cfg {Boolean} grow
51491 * @cfg {Number} growMin
51495 * @cfg {Number} growMax
51503 setWidth : function()
51507 getResizeEl : function(){
51510 });//<script type="text/javasscript">
51514 * @class Roo.DDView
51515 * A DnD enabled version of Roo.View.
51516 * @param {Element/String} container The Element in which to create the View.
51517 * @param {String} tpl The template string used to create the markup for each element of the View
51518 * @param {Object} config The configuration properties. These include all the config options of
51519 * {@link Roo.View} plus some specific to this class.<br>
51521 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51522 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51524 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51525 .x-view-drag-insert-above {
51526 border-top:1px dotted #3366cc;
51528 .x-view-drag-insert-below {
51529 border-bottom:1px dotted #3366cc;
51535 Roo.DDView = function(container, tpl, config) {
51536 Roo.DDView.superclass.constructor.apply(this, arguments);
51537 this.getEl().setStyle("outline", "0px none");
51538 this.getEl().unselectable();
51539 if (this.dragGroup) {
51540 this.setDraggable(this.dragGroup.split(","));
51542 if (this.dropGroup) {
51543 this.setDroppable(this.dropGroup.split(","));
51545 if (this.deletable) {
51546 this.setDeletable();
51548 this.isDirtyFlag = false;
51554 Roo.extend(Roo.DDView, Roo.View, {
51555 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51556 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51557 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51558 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51562 reset: Roo.emptyFn,
51564 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51566 validate: function() {
51570 destroy: function() {
51571 this.purgeListeners();
51572 this.getEl.removeAllListeners();
51573 this.getEl().remove();
51574 if (this.dragZone) {
51575 if (this.dragZone.destroy) {
51576 this.dragZone.destroy();
51579 if (this.dropZone) {
51580 if (this.dropZone.destroy) {
51581 this.dropZone.destroy();
51586 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51587 getName: function() {
51591 /** Loads the View from a JSON string representing the Records to put into the Store. */
51592 setValue: function(v) {
51594 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51597 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51598 this.store.proxy = new Roo.data.MemoryProxy(data);
51602 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51603 getValue: function() {
51605 this.store.each(function(rec) {
51606 result += rec.id + ',';
51608 return result.substr(0, result.length - 1) + ')';
51611 getIds: function() {
51612 var i = 0, result = new Array(this.store.getCount());
51613 this.store.each(function(rec) {
51614 result[i++] = rec.id;
51619 isDirty: function() {
51620 return this.isDirtyFlag;
51624 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51625 * whole Element becomes the target, and this causes the drop gesture to append.
51627 getTargetFromEvent : function(e) {
51628 var target = e.getTarget();
51629 while ((target !== null) && (target.parentNode != this.el.dom)) {
51630 target = target.parentNode;
51633 target = this.el.dom.lastChild || this.el.dom;
51639 * Create the drag data which consists of an object which has the property "ddel" as
51640 * the drag proxy element.
51642 getDragData : function(e) {
51643 var target = this.findItemFromChild(e.getTarget());
51645 this.handleSelection(e);
51646 var selNodes = this.getSelectedNodes();
51649 copy: this.copy || (this.allowCopy && e.ctrlKey),
51653 var selectedIndices = this.getSelectedIndexes();
51654 for (var i = 0; i < selectedIndices.length; i++) {
51655 dragData.records.push(this.store.getAt(selectedIndices[i]));
51657 if (selNodes.length == 1) {
51658 dragData.ddel = target.cloneNode(true); // the div element
51660 var div = document.createElement('div'); // create the multi element drag "ghost"
51661 div.className = 'multi-proxy';
51662 for (var i = 0, len = selNodes.length; i < len; i++) {
51663 div.appendChild(selNodes[i].cloneNode(true));
51665 dragData.ddel = div;
51667 //console.log(dragData)
51668 //console.log(dragData.ddel.innerHTML)
51671 //console.log('nodragData')
51675 /** Specify to which ddGroup items in this DDView may be dragged. */
51676 setDraggable: function(ddGroup) {
51677 if (ddGroup instanceof Array) {
51678 Roo.each(ddGroup, this.setDraggable, this);
51681 if (this.dragZone) {
51682 this.dragZone.addToGroup(ddGroup);
51684 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51685 containerScroll: true,
51689 // Draggability implies selection. DragZone's mousedown selects the element.
51690 if (!this.multiSelect) { this.singleSelect = true; }
51692 // Wire the DragZone's handlers up to methods in *this*
51693 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51697 /** Specify from which ddGroup this DDView accepts drops. */
51698 setDroppable: function(ddGroup) {
51699 if (ddGroup instanceof Array) {
51700 Roo.each(ddGroup, this.setDroppable, this);
51703 if (this.dropZone) {
51704 this.dropZone.addToGroup(ddGroup);
51706 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51707 containerScroll: true,
51711 // Wire the DropZone's handlers up to methods in *this*
51712 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51713 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51714 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51715 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51716 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51720 /** Decide whether to drop above or below a View node. */
51721 getDropPoint : function(e, n, dd){
51722 if (n == this.el.dom) { return "above"; }
51723 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51724 var c = t + (b - t) / 2;
51725 var y = Roo.lib.Event.getPageY(e);
51733 onNodeEnter : function(n, dd, e, data){
51737 onNodeOver : function(n, dd, e, data){
51738 var pt = this.getDropPoint(e, n, dd);
51739 // set the insert point style on the target node
51740 var dragElClass = this.dropNotAllowed;
51743 if (pt == "above"){
51744 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51745 targetElClass = "x-view-drag-insert-above";
51747 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51748 targetElClass = "x-view-drag-insert-below";
51750 if (this.lastInsertClass != targetElClass){
51751 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51752 this.lastInsertClass = targetElClass;
51755 return dragElClass;
51758 onNodeOut : function(n, dd, e, data){
51759 this.removeDropIndicators(n);
51762 onNodeDrop : function(n, dd, e, data){
51763 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51766 var pt = this.getDropPoint(e, n, dd);
51767 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51768 if (pt == "below") { insertAt++; }
51769 for (var i = 0; i < data.records.length; i++) {
51770 var r = data.records[i];
51771 var dup = this.store.getById(r.id);
51772 if (dup && (dd != this.dragZone)) {
51773 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51776 this.store.insert(insertAt++, r.copy());
51778 data.source.isDirtyFlag = true;
51780 this.store.insert(insertAt++, r);
51782 this.isDirtyFlag = true;
51785 this.dragZone.cachedTarget = null;
51789 removeDropIndicators : function(n){
51791 Roo.fly(n).removeClass([
51792 "x-view-drag-insert-above",
51793 "x-view-drag-insert-below"]);
51794 this.lastInsertClass = "_noclass";
51799 * Utility method. Add a delete option to the DDView's context menu.
51800 * @param {String} imageUrl The URL of the "delete" icon image.
51802 setDeletable: function(imageUrl) {
51803 if (!this.singleSelect && !this.multiSelect) {
51804 this.singleSelect = true;
51806 var c = this.getContextMenu();
51807 this.contextMenu.on("itemclick", function(item) {
51810 this.remove(this.getSelectedIndexes());
51814 this.contextMenu.add({
51821 /** Return the context menu for this DDView. */
51822 getContextMenu: function() {
51823 if (!this.contextMenu) {
51824 // Create the View's context menu
51825 this.contextMenu = new Roo.menu.Menu({
51826 id: this.id + "-contextmenu"
51828 this.el.on("contextmenu", this.showContextMenu, this);
51830 return this.contextMenu;
51833 disableContextMenu: function() {
51834 if (this.contextMenu) {
51835 this.el.un("contextmenu", this.showContextMenu, this);
51839 showContextMenu: function(e, item) {
51840 item = this.findItemFromChild(e.getTarget());
51843 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51844 this.contextMenu.showAt(e.getXY());
51849 * Remove {@link Roo.data.Record}s at the specified indices.
51850 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
51852 remove: function(selectedIndices) {
51853 selectedIndices = [].concat(selectedIndices);
51854 for (var i = 0; i < selectedIndices.length; i++) {
51855 var rec = this.store.getAt(selectedIndices[i]);
51856 this.store.remove(rec);
51861 * Double click fires the event, but also, if this is draggable, and there is only one other
51862 * related DropZone, it transfers the selected node.
51864 onDblClick : function(e){
51865 var item = this.findItemFromChild(e.getTarget());
51867 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
51870 if (this.dragGroup) {
51871 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
51872 while (targets.indexOf(this.dropZone) > -1) {
51873 targets.remove(this.dropZone);
51875 if (targets.length == 1) {
51876 this.dragZone.cachedTarget = null;
51877 var el = Roo.get(targets[0].getEl());
51878 var box = el.getBox(true);
51879 targets[0].onNodeDrop(el.dom, {
51881 xy: [box.x, box.y + box.height - 1]
51882 }, null, this.getDragData(e));
51888 handleSelection: function(e) {
51889 this.dragZone.cachedTarget = null;
51890 var item = this.findItemFromChild(e.getTarget());
51892 this.clearSelections(true);
51895 if (item && (this.multiSelect || this.singleSelect)){
51896 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
51897 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
51898 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
51899 this.unselect(item);
51901 this.select(item, this.multiSelect && e.ctrlKey);
51902 this.lastSelection = item;
51907 onItemClick : function(item, index, e){
51908 if(this.fireEvent("beforeclick", this, index, item, e) === false){
51914 unselect : function(nodeInfo, suppressEvent){
51915 var node = this.getNode(nodeInfo);
51916 if(node && this.isSelected(node)){
51917 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
51918 Roo.fly(node).removeClass(this.selectedClass);
51919 this.selections.remove(node);
51920 if(!suppressEvent){
51921 this.fireEvent("selectionchange", this, this.selections);
51929 * Ext JS Library 1.1.1
51930 * Copyright(c) 2006-2007, Ext JS, LLC.
51932 * Originally Released Under LGPL - original licence link has changed is not relivant.
51935 * <script type="text/javascript">
51939 * @class Roo.LayoutManager
51940 * @extends Roo.util.Observable
51941 * Base class for layout managers.
51943 Roo.LayoutManager = function(container, config){
51944 Roo.LayoutManager.superclass.constructor.call(this);
51945 this.el = Roo.get(container);
51946 // ie scrollbar fix
51947 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
51948 document.body.scroll = "no";
51949 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
51950 this.el.position('relative');
51952 this.id = this.el.id;
51953 this.el.addClass("x-layout-container");
51954 /** false to disable window resize monitoring @type Boolean */
51955 this.monitorWindowResize = true;
51960 * Fires when a layout is performed.
51961 * @param {Roo.LayoutManager} this
51965 * @event regionresized
51966 * Fires when the user resizes a region.
51967 * @param {Roo.LayoutRegion} region The resized region
51968 * @param {Number} newSize The new size (width for east/west, height for north/south)
51970 "regionresized" : true,
51972 * @event regioncollapsed
51973 * Fires when a region is collapsed.
51974 * @param {Roo.LayoutRegion} region The collapsed region
51976 "regioncollapsed" : true,
51978 * @event regionexpanded
51979 * Fires when a region is expanded.
51980 * @param {Roo.LayoutRegion} region The expanded region
51982 "regionexpanded" : true
51984 this.updating = false;
51985 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
51988 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
51990 * Returns true if this layout is currently being updated
51991 * @return {Boolean}
51993 isUpdating : function(){
51994 return this.updating;
51998 * Suspend the LayoutManager from doing auto-layouts while
51999 * making multiple add or remove calls
52001 beginUpdate : function(){
52002 this.updating = true;
52006 * Restore auto-layouts and optionally disable the manager from performing a layout
52007 * @param {Boolean} noLayout true to disable a layout update
52009 endUpdate : function(noLayout){
52010 this.updating = false;
52016 layout: function(){
52020 onRegionResized : function(region, newSize){
52021 this.fireEvent("regionresized", region, newSize);
52025 onRegionCollapsed : function(region){
52026 this.fireEvent("regioncollapsed", region);
52029 onRegionExpanded : function(region){
52030 this.fireEvent("regionexpanded", region);
52034 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
52035 * performs box-model adjustments.
52036 * @return {Object} The size as an object {width: (the width), height: (the height)}
52038 getViewSize : function(){
52040 if(this.el.dom != document.body){
52041 size = this.el.getSize();
52043 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
52045 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
52046 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
52051 * Returns the Element this layout is bound to.
52052 * @return {Roo.Element}
52054 getEl : function(){
52059 * Returns the specified region.
52060 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
52061 * @return {Roo.LayoutRegion}
52063 getRegion : function(target){
52064 return this.regions[target.toLowerCase()];
52067 onWindowResize : function(){
52068 if(this.monitorWindowResize){
52074 * Ext JS Library 1.1.1
52075 * Copyright(c) 2006-2007, Ext JS, LLC.
52077 * Originally Released Under LGPL - original licence link has changed is not relivant.
52080 * <script type="text/javascript">
52083 * @class Roo.BorderLayout
52084 * @extends Roo.LayoutManager
52085 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52086 * please see: <br><br>
52087 * <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>
52088 * <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>
52091 var layout = new Roo.BorderLayout(document.body, {
52125 preferredTabWidth: 150
52130 var CP = Roo.ContentPanel;
52132 layout.beginUpdate();
52133 layout.add("north", new CP("north", "North"));
52134 layout.add("south", new CP("south", {title: "South", closable: true}));
52135 layout.add("west", new CP("west", {title: "West"}));
52136 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52137 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52138 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52139 layout.getRegion("center").showPanel("center1");
52140 layout.endUpdate();
52143 <b>The container the layout is rendered into can be either the body element or any other element.
52144 If it is not the body element, the container needs to either be an absolute positioned element,
52145 or you will need to add "position:relative" to the css of the container. You will also need to specify
52146 the container size if it is not the body element.</b>
52149 * Create a new BorderLayout
52150 * @param {String/HTMLElement/Element} container The container this layout is bound to
52151 * @param {Object} config Configuration options
52153 Roo.BorderLayout = function(container, config){
52154 config = config || {};
52155 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52156 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52157 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52158 var target = this.factory.validRegions[i];
52159 if(config[target]){
52160 this.addRegion(target, config[target]);
52165 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52167 * Creates and adds a new region if it doesn't already exist.
52168 * @param {String} target The target region key (north, south, east, west or center).
52169 * @param {Object} config The regions config object
52170 * @return {BorderLayoutRegion} The new region
52172 addRegion : function(target, config){
52173 if(!this.regions[target]){
52174 var r = this.factory.create(target, this, config);
52175 this.bindRegion(target, r);
52177 return this.regions[target];
52181 bindRegion : function(name, r){
52182 this.regions[name] = r;
52183 r.on("visibilitychange", this.layout, this);
52184 r.on("paneladded", this.layout, this);
52185 r.on("panelremoved", this.layout, this);
52186 r.on("invalidated", this.layout, this);
52187 r.on("resized", this.onRegionResized, this);
52188 r.on("collapsed", this.onRegionCollapsed, this);
52189 r.on("expanded", this.onRegionExpanded, this);
52193 * Performs a layout update.
52195 layout : function(){
52196 if(this.updating) {
52199 var size = this.getViewSize();
52200 var w = size.width;
52201 var h = size.height;
52206 //var x = 0, y = 0;
52208 var rs = this.regions;
52209 var north = rs["north"];
52210 var south = rs["south"];
52211 var west = rs["west"];
52212 var east = rs["east"];
52213 var center = rs["center"];
52214 //if(this.hideOnLayout){ // not supported anymore
52215 //c.el.setStyle("display", "none");
52217 if(north && north.isVisible()){
52218 var b = north.getBox();
52219 var m = north.getMargins();
52220 b.width = w - (m.left+m.right);
52223 centerY = b.height + b.y + m.bottom;
52224 centerH -= centerY;
52225 north.updateBox(this.safeBox(b));
52227 if(south && south.isVisible()){
52228 var b = south.getBox();
52229 var m = south.getMargins();
52230 b.width = w - (m.left+m.right);
52232 var totalHeight = (b.height + m.top + m.bottom);
52233 b.y = h - totalHeight + m.top;
52234 centerH -= totalHeight;
52235 south.updateBox(this.safeBox(b));
52237 if(west && west.isVisible()){
52238 var b = west.getBox();
52239 var m = west.getMargins();
52240 b.height = centerH - (m.top+m.bottom);
52242 b.y = centerY + m.top;
52243 var totalWidth = (b.width + m.left + m.right);
52244 centerX += totalWidth;
52245 centerW -= totalWidth;
52246 west.updateBox(this.safeBox(b));
52248 if(east && east.isVisible()){
52249 var b = east.getBox();
52250 var m = east.getMargins();
52251 b.height = centerH - (m.top+m.bottom);
52252 var totalWidth = (b.width + m.left + m.right);
52253 b.x = w - totalWidth + m.left;
52254 b.y = centerY + m.top;
52255 centerW -= totalWidth;
52256 east.updateBox(this.safeBox(b));
52259 var m = center.getMargins();
52261 x: centerX + m.left,
52262 y: centerY + m.top,
52263 width: centerW - (m.left+m.right),
52264 height: centerH - (m.top+m.bottom)
52266 //if(this.hideOnLayout){
52267 //center.el.setStyle("display", "block");
52269 center.updateBox(this.safeBox(centerBox));
52272 this.fireEvent("layout", this);
52276 safeBox : function(box){
52277 box.width = Math.max(0, box.width);
52278 box.height = Math.max(0, box.height);
52283 * Adds a ContentPanel (or subclass) to this layout.
52284 * @param {String} target The target region key (north, south, east, west or center).
52285 * @param {Roo.ContentPanel} panel The panel to add
52286 * @return {Roo.ContentPanel} The added panel
52288 add : function(target, panel){
52290 target = target.toLowerCase();
52291 return this.regions[target].add(panel);
52295 * Remove a ContentPanel (or subclass) to this layout.
52296 * @param {String} target The target region key (north, south, east, west or center).
52297 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52298 * @return {Roo.ContentPanel} The removed panel
52300 remove : function(target, panel){
52301 target = target.toLowerCase();
52302 return this.regions[target].remove(panel);
52306 * Searches all regions for a panel with the specified id
52307 * @param {String} panelId
52308 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52310 findPanel : function(panelId){
52311 var rs = this.regions;
52312 for(var target in rs){
52313 if(typeof rs[target] != "function"){
52314 var p = rs[target].getPanel(panelId);
52324 * Searches all regions for a panel with the specified id and activates (shows) it.
52325 * @param {String/ContentPanel} panelId The panels id or the panel itself
52326 * @return {Roo.ContentPanel} The shown panel or null
52328 showPanel : function(panelId) {
52329 var rs = this.regions;
52330 for(var target in rs){
52331 var r = rs[target];
52332 if(typeof r != "function"){
52333 if(r.hasPanel(panelId)){
52334 return r.showPanel(panelId);
52342 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52343 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52345 restoreState : function(provider){
52347 provider = Roo.state.Manager;
52349 var sm = new Roo.LayoutStateManager();
52350 sm.init(this, provider);
52354 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52355 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52356 * a valid ContentPanel config object. Example:
52358 // Create the main layout
52359 var layout = new Roo.BorderLayout('main-ct', {
52370 // Create and add multiple ContentPanels at once via configs
52373 id: 'source-files',
52375 title:'Ext Source Files',
52388 * @param {Object} regions An object containing ContentPanel configs by region name
52390 batchAdd : function(regions){
52391 this.beginUpdate();
52392 for(var rname in regions){
52393 var lr = this.regions[rname];
52395 this.addTypedPanels(lr, regions[rname]);
52402 addTypedPanels : function(lr, ps){
52403 if(typeof ps == 'string'){
52404 lr.add(new Roo.ContentPanel(ps));
52406 else if(ps instanceof Array){
52407 for(var i =0, len = ps.length; i < len; i++){
52408 this.addTypedPanels(lr, ps[i]);
52411 else if(!ps.events){ // raw config?
52413 delete ps.el; // prevent conflict
52414 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52416 else { // panel object assumed!
52421 * Adds a xtype elements to the layout.
52425 xtype : 'ContentPanel',
52432 xtype : 'NestedLayoutPanel',
52438 items : [ ... list of content panels or nested layout panels.. ]
52442 * @param {Object} cfg Xtype definition of item to add.
52444 addxtype : function(cfg)
52446 // basically accepts a pannel...
52447 // can accept a layout region..!?!?
52448 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52450 if (!cfg.xtype.match(/Panel$/)) {
52455 if (typeof(cfg.region) == 'undefined') {
52456 Roo.log("Failed to add Panel, region was not set");
52460 var region = cfg.region;
52466 xitems = cfg.items;
52473 case 'ContentPanel': // ContentPanel (el, cfg)
52474 case 'ScrollPanel': // ContentPanel (el, cfg)
52476 if(cfg.autoCreate) {
52477 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52479 var el = this.el.createChild();
52480 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52483 this.add(region, ret);
52487 case 'TreePanel': // our new panel!
52488 cfg.el = this.el.createChild();
52489 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52490 this.add(region, ret);
52493 case 'NestedLayoutPanel':
52494 // create a new Layout (which is a Border Layout...
52495 var el = this.el.createChild();
52496 var clayout = cfg.layout;
52498 clayout.items = clayout.items || [];
52499 // replace this exitems with the clayout ones..
52500 xitems = clayout.items;
52503 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52504 cfg.background = false;
52506 var layout = new Roo.BorderLayout(el, clayout);
52508 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52509 //console.log('adding nested layout panel ' + cfg.toSource());
52510 this.add(region, ret);
52511 nb = {}; /// find first...
52516 // needs grid and region
52518 //var el = this.getRegion(region).el.createChild();
52519 var el = this.el.createChild();
52520 // create the grid first...
52522 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52524 if (region == 'center' && this.active ) {
52525 cfg.background = false;
52527 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52529 this.add(region, ret);
52530 if (cfg.background) {
52531 ret.on('activate', function(gp) {
52532 if (!gp.grid.rendered) {
52547 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52549 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52550 this.add(region, ret);
52553 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52557 // GridPanel (grid, cfg)
52560 this.beginUpdate();
52564 Roo.each(xitems, function(i) {
52565 region = nb && i.region ? i.region : false;
52567 var add = ret.addxtype(i);
52570 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52571 if (!i.background) {
52572 abn[region] = nb[region] ;
52579 // make the last non-background panel active..
52580 //if (nb) { Roo.log(abn); }
52583 for(var r in abn) {
52584 region = this.getRegion(r);
52586 // tried using nb[r], but it does not work..
52588 region.showPanel(abn[r]);
52599 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52600 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52601 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52602 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52605 var CP = Roo.ContentPanel;
52607 var layout = Roo.BorderLayout.create({
52611 panels: [new CP("north", "North")]
52620 panels: [new CP("west", {title: "West"})]
52629 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52638 panels: [new CP("south", {title: "South", closable: true})]
52645 preferredTabWidth: 150,
52647 new CP("center1", {title: "Close Me", closable: true}),
52648 new CP("center2", {title: "Center Panel", closable: false})
52653 layout.getRegion("center").showPanel("center1");
52658 Roo.BorderLayout.create = function(config, targetEl){
52659 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52660 layout.beginUpdate();
52661 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52662 for(var j = 0, jlen = regions.length; j < jlen; j++){
52663 var lr = regions[j];
52664 if(layout.regions[lr] && config[lr].panels){
52665 var r = layout.regions[lr];
52666 var ps = config[lr].panels;
52667 layout.addTypedPanels(r, ps);
52670 layout.endUpdate();
52675 Roo.BorderLayout.RegionFactory = {
52677 validRegions : ["north","south","east","west","center"],
52680 create : function(target, mgr, config){
52681 target = target.toLowerCase();
52682 if(config.lightweight || config.basic){
52683 return new Roo.BasicLayoutRegion(mgr, config, target);
52687 return new Roo.NorthLayoutRegion(mgr, config);
52689 return new Roo.SouthLayoutRegion(mgr, config);
52691 return new Roo.EastLayoutRegion(mgr, config);
52693 return new Roo.WestLayoutRegion(mgr, config);
52695 return new Roo.CenterLayoutRegion(mgr, config);
52697 throw 'Layout region "'+target+'" not supported.';
52701 * Ext JS Library 1.1.1
52702 * Copyright(c) 2006-2007, Ext JS, LLC.
52704 * Originally Released Under LGPL - original licence link has changed is not relivant.
52707 * <script type="text/javascript">
52711 * @class Roo.BasicLayoutRegion
52712 * @extends Roo.util.Observable
52713 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52714 * and does not have a titlebar, tabs or any other features. All it does is size and position
52715 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52717 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52719 this.position = pos;
52722 * @scope Roo.BasicLayoutRegion
52726 * @event beforeremove
52727 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52728 * @param {Roo.LayoutRegion} this
52729 * @param {Roo.ContentPanel} panel The panel
52730 * @param {Object} e The cancel event object
52732 "beforeremove" : true,
52734 * @event invalidated
52735 * Fires when the layout for this region is changed.
52736 * @param {Roo.LayoutRegion} this
52738 "invalidated" : true,
52740 * @event visibilitychange
52741 * Fires when this region is shown or hidden
52742 * @param {Roo.LayoutRegion} this
52743 * @param {Boolean} visibility true or false
52745 "visibilitychange" : true,
52747 * @event paneladded
52748 * Fires when a panel is added.
52749 * @param {Roo.LayoutRegion} this
52750 * @param {Roo.ContentPanel} panel The panel
52752 "paneladded" : true,
52754 * @event panelremoved
52755 * Fires when a panel is removed.
52756 * @param {Roo.LayoutRegion} this
52757 * @param {Roo.ContentPanel} panel The panel
52759 "panelremoved" : true,
52761 * @event beforecollapse
52762 * Fires when this region before collapse.
52763 * @param {Roo.LayoutRegion} this
52765 "beforecollapse" : true,
52768 * Fires when this region is collapsed.
52769 * @param {Roo.LayoutRegion} this
52771 "collapsed" : true,
52774 * Fires when this region is expanded.
52775 * @param {Roo.LayoutRegion} this
52780 * Fires when this region is slid into view.
52781 * @param {Roo.LayoutRegion} this
52783 "slideshow" : true,
52786 * Fires when this region slides out of view.
52787 * @param {Roo.LayoutRegion} this
52789 "slidehide" : true,
52791 * @event panelactivated
52792 * Fires when a panel is activated.
52793 * @param {Roo.LayoutRegion} this
52794 * @param {Roo.ContentPanel} panel The activated panel
52796 "panelactivated" : true,
52799 * Fires when the user resizes this region.
52800 * @param {Roo.LayoutRegion} this
52801 * @param {Number} newSize The new size (width for east/west, height for north/south)
52805 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52806 this.panels = new Roo.util.MixedCollection();
52807 this.panels.getKey = this.getPanelId.createDelegate(this);
52809 this.activePanel = null;
52810 // ensure listeners are added...
52812 if (config.listeners || config.events) {
52813 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52814 listeners : config.listeners || {},
52815 events : config.events || {}
52819 if(skipConfig !== true){
52820 this.applyConfig(config);
52824 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52825 getPanelId : function(p){
52829 applyConfig : function(config){
52830 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52831 this.config = config;
52836 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
52837 * the width, for horizontal (north, south) the height.
52838 * @param {Number} newSize The new width or height
52840 resizeTo : function(newSize){
52841 var el = this.el ? this.el :
52842 (this.activePanel ? this.activePanel.getEl() : null);
52844 switch(this.position){
52847 el.setWidth(newSize);
52848 this.fireEvent("resized", this, newSize);
52852 el.setHeight(newSize);
52853 this.fireEvent("resized", this, newSize);
52859 getBox : function(){
52860 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
52863 getMargins : function(){
52864 return this.margins;
52867 updateBox : function(box){
52869 var el = this.activePanel.getEl();
52870 el.dom.style.left = box.x + "px";
52871 el.dom.style.top = box.y + "px";
52872 this.activePanel.setSize(box.width, box.height);
52876 * Returns the container element for this region.
52877 * @return {Roo.Element}
52879 getEl : function(){
52880 return this.activePanel;
52884 * Returns true if this region is currently visible.
52885 * @return {Boolean}
52887 isVisible : function(){
52888 return this.activePanel ? true : false;
52891 setActivePanel : function(panel){
52892 panel = this.getPanel(panel);
52893 if(this.activePanel && this.activePanel != panel){
52894 this.activePanel.setActiveState(false);
52895 this.activePanel.getEl().setLeftTop(-10000,-10000);
52897 this.activePanel = panel;
52898 panel.setActiveState(true);
52900 panel.setSize(this.box.width, this.box.height);
52902 this.fireEvent("panelactivated", this, panel);
52903 this.fireEvent("invalidated");
52907 * Show the specified panel.
52908 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
52909 * @return {Roo.ContentPanel} The shown panel or null
52911 showPanel : function(panel){
52912 if(panel = this.getPanel(panel)){
52913 this.setActivePanel(panel);
52919 * Get the active panel for this region.
52920 * @return {Roo.ContentPanel} The active panel or null
52922 getActivePanel : function(){
52923 return this.activePanel;
52927 * Add the passed ContentPanel(s)
52928 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52929 * @return {Roo.ContentPanel} The panel added (if only one was added)
52931 add : function(panel){
52932 if(arguments.length > 1){
52933 for(var i = 0, len = arguments.length; i < len; i++) {
52934 this.add(arguments[i]);
52938 if(this.hasPanel(panel)){
52939 this.showPanel(panel);
52942 var el = panel.getEl();
52943 if(el.dom.parentNode != this.mgr.el.dom){
52944 this.mgr.el.dom.appendChild(el.dom);
52946 if(panel.setRegion){
52947 panel.setRegion(this);
52949 this.panels.add(panel);
52950 el.setStyle("position", "absolute");
52951 if(!panel.background){
52952 this.setActivePanel(panel);
52953 if(this.config.initialSize && this.panels.getCount()==1){
52954 this.resizeTo(this.config.initialSize);
52957 this.fireEvent("paneladded", this, panel);
52962 * Returns true if the panel is in this region.
52963 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52964 * @return {Boolean}
52966 hasPanel : function(panel){
52967 if(typeof panel == "object"){ // must be panel obj
52968 panel = panel.getId();
52970 return this.getPanel(panel) ? true : false;
52974 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52975 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52976 * @param {Boolean} preservePanel Overrides the config preservePanel option
52977 * @return {Roo.ContentPanel} The panel that was removed
52979 remove : function(panel, preservePanel){
52980 panel = this.getPanel(panel);
52985 this.fireEvent("beforeremove", this, panel, e);
52986 if(e.cancel === true){
52989 var panelId = panel.getId();
52990 this.panels.removeKey(panelId);
52995 * Returns the panel specified or null if it's not in this region.
52996 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52997 * @return {Roo.ContentPanel}
52999 getPanel : function(id){
53000 if(typeof id == "object"){ // must be panel obj
53003 return this.panels.get(id);
53007 * Returns this regions position (north/south/east/west/center).
53010 getPosition: function(){
53011 return this.position;
53015 * Ext JS Library 1.1.1
53016 * Copyright(c) 2006-2007, Ext JS, LLC.
53018 * Originally Released Under LGPL - original licence link has changed is not relivant.
53021 * <script type="text/javascript">
53025 * @class Roo.LayoutRegion
53026 * @extends Roo.BasicLayoutRegion
53027 * This class represents a region in a layout manager.
53028 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
53029 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
53030 * @cfg {Boolean} floatable False to disable floating (defaults to true)
53031 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
53032 * @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})
53033 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
53034 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
53035 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
53036 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
53037 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
53038 * @cfg {String} title The title for the region (overrides panel titles)
53039 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
53040 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
53041 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
53042 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
53043 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
53044 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
53045 * the space available, similar to FireFox 1.5 tabs (defaults to false)
53046 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
53047 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
53048 * @cfg {Boolean} showPin True to show a pin button
53049 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
53050 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
53051 * @cfg {Boolean} disableTabTips True to disable tab tooltips
53052 * @cfg {Number} width For East/West panels
53053 * @cfg {Number} height For North/South panels
53054 * @cfg {Boolean} split To show the splitter
53055 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
53057 Roo.LayoutRegion = function(mgr, config, pos){
53058 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
53059 var dh = Roo.DomHelper;
53060 /** This region's container element
53061 * @type Roo.Element */
53062 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
53063 /** This region's title element
53064 * @type Roo.Element */
53066 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
53067 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
53068 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
53070 this.titleEl.enableDisplayMode();
53071 /** This region's title text element
53072 * @type HTMLElement */
53073 this.titleTextEl = this.titleEl.dom.firstChild;
53074 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53075 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53076 this.closeBtn.enableDisplayMode();
53077 this.closeBtn.on("click", this.closeClicked, this);
53078 this.closeBtn.hide();
53080 this.createBody(config);
53081 this.visible = true;
53082 this.collapsed = false;
53084 if(config.hideWhenEmpty){
53086 this.on("paneladded", this.validateVisibility, this);
53087 this.on("panelremoved", this.validateVisibility, this);
53089 this.applyConfig(config);
53092 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53094 createBody : function(){
53095 /** This region's body element
53096 * @type Roo.Element */
53097 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53100 applyConfig : function(c){
53101 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53102 var dh = Roo.DomHelper;
53103 if(c.titlebar !== false){
53104 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53105 this.collapseBtn.on("click", this.collapse, this);
53106 this.collapseBtn.enableDisplayMode();
53108 if(c.showPin === true || this.showPin){
53109 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53110 this.stickBtn.enableDisplayMode();
53111 this.stickBtn.on("click", this.expand, this);
53112 this.stickBtn.hide();
53115 /** This region's collapsed element
53116 * @type Roo.Element */
53117 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53118 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53120 if(c.floatable !== false){
53121 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53122 this.collapsedEl.on("click", this.collapseClick, this);
53125 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53126 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53127 id: "message", unselectable: "on", style:{"float":"left"}});
53128 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53130 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53131 this.expandBtn.on("click", this.expand, this);
53133 if(this.collapseBtn){
53134 this.collapseBtn.setVisible(c.collapsible == true);
53136 this.cmargins = c.cmargins || this.cmargins ||
53137 (this.position == "west" || this.position == "east" ?
53138 {top: 0, left: 2, right:2, bottom: 0} :
53139 {top: 2, left: 0, right:0, bottom: 2});
53140 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53141 this.bottomTabs = c.tabPosition != "top";
53142 this.autoScroll = c.autoScroll || false;
53143 if(this.autoScroll){
53144 this.bodyEl.setStyle("overflow", "auto");
53146 this.bodyEl.setStyle("overflow", "hidden");
53148 //if(c.titlebar !== false){
53149 if((!c.titlebar && !c.title) || c.titlebar === false){
53150 this.titleEl.hide();
53152 this.titleEl.show();
53154 this.titleTextEl.innerHTML = c.title;
53158 this.duration = c.duration || .30;
53159 this.slideDuration = c.slideDuration || .45;
53162 this.collapse(true);
53169 * Returns true if this region is currently visible.
53170 * @return {Boolean}
53172 isVisible : function(){
53173 return this.visible;
53177 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53178 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53180 setCollapsedTitle : function(title){
53181 title = title || " ";
53182 if(this.collapsedTitleTextEl){
53183 this.collapsedTitleTextEl.innerHTML = title;
53187 getBox : function(){
53189 if(!this.collapsed){
53190 b = this.el.getBox(false, true);
53192 b = this.collapsedEl.getBox(false, true);
53197 getMargins : function(){
53198 return this.collapsed ? this.cmargins : this.margins;
53201 highlight : function(){
53202 this.el.addClass("x-layout-panel-dragover");
53205 unhighlight : function(){
53206 this.el.removeClass("x-layout-panel-dragover");
53209 updateBox : function(box){
53211 if(!this.collapsed){
53212 this.el.dom.style.left = box.x + "px";
53213 this.el.dom.style.top = box.y + "px";
53214 this.updateBody(box.width, box.height);
53216 this.collapsedEl.dom.style.left = box.x + "px";
53217 this.collapsedEl.dom.style.top = box.y + "px";
53218 this.collapsedEl.setSize(box.width, box.height);
53221 this.tabs.autoSizeTabs();
53225 updateBody : function(w, h){
53227 this.el.setWidth(w);
53228 w -= this.el.getBorderWidth("rl");
53229 if(this.config.adjustments){
53230 w += this.config.adjustments[0];
53234 this.el.setHeight(h);
53235 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53236 h -= this.el.getBorderWidth("tb");
53237 if(this.config.adjustments){
53238 h += this.config.adjustments[1];
53240 this.bodyEl.setHeight(h);
53242 h = this.tabs.syncHeight(h);
53245 if(this.panelSize){
53246 w = w !== null ? w : this.panelSize.width;
53247 h = h !== null ? h : this.panelSize.height;
53249 if(this.activePanel){
53250 var el = this.activePanel.getEl();
53251 w = w !== null ? w : el.getWidth();
53252 h = h !== null ? h : el.getHeight();
53253 this.panelSize = {width: w, height: h};
53254 this.activePanel.setSize(w, h);
53256 if(Roo.isIE && this.tabs){
53257 this.tabs.el.repaint();
53262 * Returns the container element for this region.
53263 * @return {Roo.Element}
53265 getEl : function(){
53270 * Hides this region.
53273 if(!this.collapsed){
53274 this.el.dom.style.left = "-2000px";
53277 this.collapsedEl.dom.style.left = "-2000px";
53278 this.collapsedEl.hide();
53280 this.visible = false;
53281 this.fireEvent("visibilitychange", this, false);
53285 * Shows this region if it was previously hidden.
53288 if(!this.collapsed){
53291 this.collapsedEl.show();
53293 this.visible = true;
53294 this.fireEvent("visibilitychange", this, true);
53297 closeClicked : function(){
53298 if(this.activePanel){
53299 this.remove(this.activePanel);
53303 collapseClick : function(e){
53305 e.stopPropagation();
53308 e.stopPropagation();
53314 * Collapses this region.
53315 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53317 collapse : function(skipAnim, skipCheck){
53318 if(this.collapsed) {
53322 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53324 this.collapsed = true;
53326 this.split.el.hide();
53328 if(this.config.animate && skipAnim !== true){
53329 this.fireEvent("invalidated", this);
53330 this.animateCollapse();
53332 this.el.setLocation(-20000,-20000);
53334 this.collapsedEl.show();
53335 this.fireEvent("collapsed", this);
53336 this.fireEvent("invalidated", this);
53342 animateCollapse : function(){
53347 * Expands this region if it was previously collapsed.
53348 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53349 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53351 expand : function(e, skipAnim){
53353 e.stopPropagation();
53355 if(!this.collapsed || this.el.hasActiveFx()) {
53359 this.afterSlideIn();
53362 this.collapsed = false;
53363 if(this.config.animate && skipAnim !== true){
53364 this.animateExpand();
53368 this.split.el.show();
53370 this.collapsedEl.setLocation(-2000,-2000);
53371 this.collapsedEl.hide();
53372 this.fireEvent("invalidated", this);
53373 this.fireEvent("expanded", this);
53377 animateExpand : function(){
53381 initTabs : function()
53383 this.bodyEl.setStyle("overflow", "hidden");
53384 var ts = new Roo.TabPanel(
53387 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53388 disableTooltips: this.config.disableTabTips,
53389 toolbar : this.config.toolbar
53392 if(this.config.hideTabs){
53393 ts.stripWrap.setDisplayed(false);
53396 ts.resizeTabs = this.config.resizeTabs === true;
53397 ts.minTabWidth = this.config.minTabWidth || 40;
53398 ts.maxTabWidth = this.config.maxTabWidth || 250;
53399 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53400 ts.monitorResize = false;
53401 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53402 ts.bodyEl.addClass('x-layout-tabs-body');
53403 this.panels.each(this.initPanelAsTab, this);
53406 initPanelAsTab : function(panel){
53407 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53408 this.config.closeOnTab && panel.isClosable());
53409 if(panel.tabTip !== undefined){
53410 ti.setTooltip(panel.tabTip);
53412 ti.on("activate", function(){
53413 this.setActivePanel(panel);
53415 if(this.config.closeOnTab){
53416 ti.on("beforeclose", function(t, e){
53418 this.remove(panel);
53424 updatePanelTitle : function(panel, title){
53425 if(this.activePanel == panel){
53426 this.updateTitle(title);
53429 var ti = this.tabs.getTab(panel.getEl().id);
53431 if(panel.tabTip !== undefined){
53432 ti.setTooltip(panel.tabTip);
53437 updateTitle : function(title){
53438 if(this.titleTextEl && !this.config.title){
53439 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53443 setActivePanel : function(panel){
53444 panel = this.getPanel(panel);
53445 if(this.activePanel && this.activePanel != panel){
53446 this.activePanel.setActiveState(false);
53448 this.activePanel = panel;
53449 panel.setActiveState(true);
53450 if(this.panelSize){
53451 panel.setSize(this.panelSize.width, this.panelSize.height);
53454 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53456 this.updateTitle(panel.getTitle());
53458 this.fireEvent("invalidated", this);
53460 this.fireEvent("panelactivated", this, panel);
53464 * Shows the specified panel.
53465 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53466 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53468 showPanel : function(panel)
53470 panel = this.getPanel(panel);
53473 var tab = this.tabs.getTab(panel.getEl().id);
53474 if(tab.isHidden()){
53475 this.tabs.unhideTab(tab.id);
53479 this.setActivePanel(panel);
53486 * Get the active panel for this region.
53487 * @return {Roo.ContentPanel} The active panel or null
53489 getActivePanel : function(){
53490 return this.activePanel;
53493 validateVisibility : function(){
53494 if(this.panels.getCount() < 1){
53495 this.updateTitle(" ");
53496 this.closeBtn.hide();
53499 if(!this.isVisible()){
53506 * Adds the passed ContentPanel(s) to this region.
53507 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53508 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53510 add : function(panel){
53511 if(arguments.length > 1){
53512 for(var i = 0, len = arguments.length; i < len; i++) {
53513 this.add(arguments[i]);
53517 if(this.hasPanel(panel)){
53518 this.showPanel(panel);
53521 panel.setRegion(this);
53522 this.panels.add(panel);
53523 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53524 this.bodyEl.dom.appendChild(panel.getEl().dom);
53525 if(panel.background !== true){
53526 this.setActivePanel(panel);
53528 this.fireEvent("paneladded", this, panel);
53534 this.initPanelAsTab(panel);
53536 if(panel.background !== true){
53537 this.tabs.activate(panel.getEl().id);
53539 this.fireEvent("paneladded", this, panel);
53544 * Hides the tab for the specified panel.
53545 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53547 hidePanel : function(panel){
53548 if(this.tabs && (panel = this.getPanel(panel))){
53549 this.tabs.hideTab(panel.getEl().id);
53554 * Unhides the tab for a previously hidden panel.
53555 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53557 unhidePanel : function(panel){
53558 if(this.tabs && (panel = this.getPanel(panel))){
53559 this.tabs.unhideTab(panel.getEl().id);
53563 clearPanels : function(){
53564 while(this.panels.getCount() > 0){
53565 this.remove(this.panels.first());
53570 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53571 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53572 * @param {Boolean} preservePanel Overrides the config preservePanel option
53573 * @return {Roo.ContentPanel} The panel that was removed
53575 remove : function(panel, preservePanel){
53576 panel = this.getPanel(panel);
53581 this.fireEvent("beforeremove", this, panel, e);
53582 if(e.cancel === true){
53585 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53586 var panelId = panel.getId();
53587 this.panels.removeKey(panelId);
53589 document.body.appendChild(panel.getEl().dom);
53592 this.tabs.removeTab(panel.getEl().id);
53593 }else if (!preservePanel){
53594 this.bodyEl.dom.removeChild(panel.getEl().dom);
53596 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53597 var p = this.panels.first();
53598 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53599 tempEl.appendChild(p.getEl().dom);
53600 this.bodyEl.update("");
53601 this.bodyEl.dom.appendChild(p.getEl().dom);
53603 this.updateTitle(p.getTitle());
53605 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53606 this.setActivePanel(p);
53608 panel.setRegion(null);
53609 if(this.activePanel == panel){
53610 this.activePanel = null;
53612 if(this.config.autoDestroy !== false && preservePanel !== true){
53613 try{panel.destroy();}catch(e){}
53615 this.fireEvent("panelremoved", this, panel);
53620 * Returns the TabPanel component used by this region
53621 * @return {Roo.TabPanel}
53623 getTabs : function(){
53627 createTool : function(parentEl, className){
53628 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53629 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53630 btn.addClassOnOver("x-layout-tools-button-over");
53635 * Ext JS Library 1.1.1
53636 * Copyright(c) 2006-2007, Ext JS, LLC.
53638 * Originally Released Under LGPL - original licence link has changed is not relivant.
53641 * <script type="text/javascript">
53647 * @class Roo.SplitLayoutRegion
53648 * @extends Roo.LayoutRegion
53649 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53651 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53652 this.cursor = cursor;
53653 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53656 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53657 splitTip : "Drag to resize.",
53658 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53659 useSplitTips : false,
53661 applyConfig : function(config){
53662 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53665 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53666 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53667 /** The SplitBar for this region
53668 * @type Roo.SplitBar */
53669 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53670 this.split.on("moved", this.onSplitMove, this);
53671 this.split.useShim = config.useShim === true;
53672 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53673 if(this.useSplitTips){
53674 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53676 if(config.collapsible){
53677 this.split.el.on("dblclick", this.collapse, this);
53680 if(typeof config.minSize != "undefined"){
53681 this.split.minSize = config.minSize;
53683 if(typeof config.maxSize != "undefined"){
53684 this.split.maxSize = config.maxSize;
53686 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53687 this.hideSplitter();
53692 getHMaxSize : function(){
53693 var cmax = this.config.maxSize || 10000;
53694 var center = this.mgr.getRegion("center");
53695 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53698 getVMaxSize : function(){
53699 var cmax = this.config.maxSize || 10000;
53700 var center = this.mgr.getRegion("center");
53701 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53704 onSplitMove : function(split, newSize){
53705 this.fireEvent("resized", this, newSize);
53709 * Returns the {@link Roo.SplitBar} for this region.
53710 * @return {Roo.SplitBar}
53712 getSplitBar : function(){
53717 this.hideSplitter();
53718 Roo.SplitLayoutRegion.superclass.hide.call(this);
53721 hideSplitter : function(){
53723 this.split.el.setLocation(-2000,-2000);
53724 this.split.el.hide();
53730 this.split.el.show();
53732 Roo.SplitLayoutRegion.superclass.show.call(this);
53735 beforeSlide: function(){
53736 if(Roo.isGecko){// firefox overflow auto bug workaround
53737 this.bodyEl.clip();
53739 this.tabs.bodyEl.clip();
53741 if(this.activePanel){
53742 this.activePanel.getEl().clip();
53744 if(this.activePanel.beforeSlide){
53745 this.activePanel.beforeSlide();
53751 afterSlide : function(){
53752 if(Roo.isGecko){// firefox overflow auto bug workaround
53753 this.bodyEl.unclip();
53755 this.tabs.bodyEl.unclip();
53757 if(this.activePanel){
53758 this.activePanel.getEl().unclip();
53759 if(this.activePanel.afterSlide){
53760 this.activePanel.afterSlide();
53766 initAutoHide : function(){
53767 if(this.autoHide !== false){
53768 if(!this.autoHideHd){
53769 var st = new Roo.util.DelayedTask(this.slideIn, this);
53770 this.autoHideHd = {
53771 "mouseout": function(e){
53772 if(!e.within(this.el, true)){
53776 "mouseover" : function(e){
53782 this.el.on(this.autoHideHd);
53786 clearAutoHide : function(){
53787 if(this.autoHide !== false){
53788 this.el.un("mouseout", this.autoHideHd.mouseout);
53789 this.el.un("mouseover", this.autoHideHd.mouseover);
53793 clearMonitor : function(){
53794 Roo.get(document).un("click", this.slideInIf, this);
53797 // these names are backwards but not changed for compat
53798 slideOut : function(){
53799 if(this.isSlid || this.el.hasActiveFx()){
53802 this.isSlid = true;
53803 if(this.collapseBtn){
53804 this.collapseBtn.hide();
53806 this.closeBtnState = this.closeBtn.getStyle('display');
53807 this.closeBtn.hide();
53809 this.stickBtn.show();
53812 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53813 this.beforeSlide();
53814 this.el.setStyle("z-index", 10001);
53815 this.el.slideIn(this.getSlideAnchor(), {
53816 callback: function(){
53818 this.initAutoHide();
53819 Roo.get(document).on("click", this.slideInIf, this);
53820 this.fireEvent("slideshow", this);
53827 afterSlideIn : function(){
53828 this.clearAutoHide();
53829 this.isSlid = false;
53830 this.clearMonitor();
53831 this.el.setStyle("z-index", "");
53832 if(this.collapseBtn){
53833 this.collapseBtn.show();
53835 this.closeBtn.setStyle('display', this.closeBtnState);
53837 this.stickBtn.hide();
53839 this.fireEvent("slidehide", this);
53842 slideIn : function(cb){
53843 if(!this.isSlid || this.el.hasActiveFx()){
53847 this.isSlid = false;
53848 this.beforeSlide();
53849 this.el.slideOut(this.getSlideAnchor(), {
53850 callback: function(){
53851 this.el.setLeftTop(-10000, -10000);
53853 this.afterSlideIn();
53861 slideInIf : function(e){
53862 if(!e.within(this.el)){
53867 animateCollapse : function(){
53868 this.beforeSlide();
53869 this.el.setStyle("z-index", 20000);
53870 var anchor = this.getSlideAnchor();
53871 this.el.slideOut(anchor, {
53872 callback : function(){
53873 this.el.setStyle("z-index", "");
53874 this.collapsedEl.slideIn(anchor, {duration:.3});
53876 this.el.setLocation(-10000,-10000);
53878 this.fireEvent("collapsed", this);
53885 animateExpand : function(){
53886 this.beforeSlide();
53887 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
53888 this.el.setStyle("z-index", 20000);
53889 this.collapsedEl.hide({
53892 this.el.slideIn(this.getSlideAnchor(), {
53893 callback : function(){
53894 this.el.setStyle("z-index", "");
53897 this.split.el.show();
53899 this.fireEvent("invalidated", this);
53900 this.fireEvent("expanded", this);
53928 getAnchor : function(){
53929 return this.anchors[this.position];
53932 getCollapseAnchor : function(){
53933 return this.canchors[this.position];
53936 getSlideAnchor : function(){
53937 return this.sanchors[this.position];
53940 getAlignAdj : function(){
53941 var cm = this.cmargins;
53942 switch(this.position){
53958 getExpandAdj : function(){
53959 var c = this.collapsedEl, cm = this.cmargins;
53960 switch(this.position){
53962 return [-(cm.right+c.getWidth()+cm.left), 0];
53965 return [cm.right+c.getWidth()+cm.left, 0];
53968 return [0, -(cm.top+cm.bottom+c.getHeight())];
53971 return [0, cm.top+cm.bottom+c.getHeight()];
53977 * Ext JS Library 1.1.1
53978 * Copyright(c) 2006-2007, Ext JS, LLC.
53980 * Originally Released Under LGPL - original licence link has changed is not relivant.
53983 * <script type="text/javascript">
53986 * These classes are private internal classes
53988 Roo.CenterLayoutRegion = function(mgr, config){
53989 Roo.LayoutRegion.call(this, mgr, config, "center");
53990 this.visible = true;
53991 this.minWidth = config.minWidth || 20;
53992 this.minHeight = config.minHeight || 20;
53995 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
53997 // center panel can't be hidden
54001 // center panel can't be hidden
54004 getMinWidth: function(){
54005 return this.minWidth;
54008 getMinHeight: function(){
54009 return this.minHeight;
54014 Roo.NorthLayoutRegion = function(mgr, config){
54015 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
54017 this.split.placement = Roo.SplitBar.TOP;
54018 this.split.orientation = Roo.SplitBar.VERTICAL;
54019 this.split.el.addClass("x-layout-split-v");
54021 var size = config.initialSize || config.height;
54022 if(typeof size != "undefined"){
54023 this.el.setHeight(size);
54026 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
54027 orientation: Roo.SplitBar.VERTICAL,
54028 getBox : function(){
54029 if(this.collapsed){
54030 return this.collapsedEl.getBox();
54032 var box = this.el.getBox();
54034 box.height += this.split.el.getHeight();
54039 updateBox : function(box){
54040 if(this.split && !this.collapsed){
54041 box.height -= this.split.el.getHeight();
54042 this.split.el.setLeft(box.x);
54043 this.split.el.setTop(box.y+box.height);
54044 this.split.el.setWidth(box.width);
54046 if(this.collapsed){
54047 this.updateBody(box.width, null);
54049 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54053 Roo.SouthLayoutRegion = function(mgr, config){
54054 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
54056 this.split.placement = Roo.SplitBar.BOTTOM;
54057 this.split.orientation = Roo.SplitBar.VERTICAL;
54058 this.split.el.addClass("x-layout-split-v");
54060 var size = config.initialSize || config.height;
54061 if(typeof size != "undefined"){
54062 this.el.setHeight(size);
54065 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
54066 orientation: Roo.SplitBar.VERTICAL,
54067 getBox : function(){
54068 if(this.collapsed){
54069 return this.collapsedEl.getBox();
54071 var box = this.el.getBox();
54073 var sh = this.split.el.getHeight();
54080 updateBox : function(box){
54081 if(this.split && !this.collapsed){
54082 var sh = this.split.el.getHeight();
54085 this.split.el.setLeft(box.x);
54086 this.split.el.setTop(box.y-sh);
54087 this.split.el.setWidth(box.width);
54089 if(this.collapsed){
54090 this.updateBody(box.width, null);
54092 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54096 Roo.EastLayoutRegion = function(mgr, config){
54097 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54099 this.split.placement = Roo.SplitBar.RIGHT;
54100 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54101 this.split.el.addClass("x-layout-split-h");
54103 var size = config.initialSize || config.width;
54104 if(typeof size != "undefined"){
54105 this.el.setWidth(size);
54108 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54109 orientation: Roo.SplitBar.HORIZONTAL,
54110 getBox : function(){
54111 if(this.collapsed){
54112 return this.collapsedEl.getBox();
54114 var box = this.el.getBox();
54116 var sw = this.split.el.getWidth();
54123 updateBox : function(box){
54124 if(this.split && !this.collapsed){
54125 var sw = this.split.el.getWidth();
54127 this.split.el.setLeft(box.x);
54128 this.split.el.setTop(box.y);
54129 this.split.el.setHeight(box.height);
54132 if(this.collapsed){
54133 this.updateBody(null, box.height);
54135 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54139 Roo.WestLayoutRegion = function(mgr, config){
54140 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54142 this.split.placement = Roo.SplitBar.LEFT;
54143 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54144 this.split.el.addClass("x-layout-split-h");
54146 var size = config.initialSize || config.width;
54147 if(typeof size != "undefined"){
54148 this.el.setWidth(size);
54151 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
54152 orientation: Roo.SplitBar.HORIZONTAL,
54153 getBox : function(){
54154 if(this.collapsed){
54155 return this.collapsedEl.getBox();
54157 var box = this.el.getBox();
54159 box.width += this.split.el.getWidth();
54164 updateBox : function(box){
54165 if(this.split && !this.collapsed){
54166 var sw = this.split.el.getWidth();
54168 this.split.el.setLeft(box.x+box.width);
54169 this.split.el.setTop(box.y);
54170 this.split.el.setHeight(box.height);
54172 if(this.collapsed){
54173 this.updateBody(null, box.height);
54175 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54180 * Ext JS Library 1.1.1
54181 * Copyright(c) 2006-2007, Ext JS, LLC.
54183 * Originally Released Under LGPL - original licence link has changed is not relivant.
54186 * <script type="text/javascript">
54191 * Private internal class for reading and applying state
54193 Roo.LayoutStateManager = function(layout){
54194 // default empty state
54203 Roo.LayoutStateManager.prototype = {
54204 init : function(layout, provider){
54205 this.provider = provider;
54206 var state = provider.get(layout.id+"-layout-state");
54208 var wasUpdating = layout.isUpdating();
54210 layout.beginUpdate();
54212 for(var key in state){
54213 if(typeof state[key] != "function"){
54214 var rstate = state[key];
54215 var r = layout.getRegion(key);
54218 r.resizeTo(rstate.size);
54220 if(rstate.collapsed == true){
54223 r.expand(null, true);
54229 layout.endUpdate();
54231 this.state = state;
54233 this.layout = layout;
54234 layout.on("regionresized", this.onRegionResized, this);
54235 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54236 layout.on("regionexpanded", this.onRegionExpanded, this);
54239 storeState : function(){
54240 this.provider.set(this.layout.id+"-layout-state", this.state);
54243 onRegionResized : function(region, newSize){
54244 this.state[region.getPosition()].size = newSize;
54248 onRegionCollapsed : function(region){
54249 this.state[region.getPosition()].collapsed = true;
54253 onRegionExpanded : function(region){
54254 this.state[region.getPosition()].collapsed = false;
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">
54268 * @class Roo.ContentPanel
54269 * @extends Roo.util.Observable
54270 * A basic ContentPanel element.
54271 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54272 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54273 * @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
54274 * @cfg {Boolean} closable True if the panel can be closed/removed
54275 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54276 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54277 * @cfg {Toolbar} toolbar A toolbar for this panel
54278 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54279 * @cfg {String} title The title for this panel
54280 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54281 * @cfg {String} url Calls {@link #setUrl} with this value
54282 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54283 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54284 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54285 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54286 * @cfg {String} style Extra style to add to the content panel
54289 * Create a new ContentPanel.
54290 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54291 * @param {String/Object} config A string to set only the title or a config object
54292 * @param {String} content (optional) Set the HTML content for this panel
54293 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54295 Roo.ContentPanel = function(el, config, content){
54299 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54303 if (config && config.parentLayout) {
54304 el = config.parentLayout.el.createChild();
54307 if(el.autoCreate){ // xtype is available if this is called from factory
54311 this.el = Roo.get(el);
54312 if(!this.el && config && config.autoCreate){
54313 if(typeof config.autoCreate == "object"){
54314 if(!config.autoCreate.id){
54315 config.autoCreate.id = config.id||el;
54317 this.el = Roo.DomHelper.append(document.body,
54318 config.autoCreate, true);
54320 this.el = Roo.DomHelper.append(document.body,
54321 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54326 this.closable = false;
54327 this.loaded = false;
54328 this.active = false;
54329 if(typeof config == "string"){
54330 this.title = config;
54332 Roo.apply(this, config);
54335 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54336 this.wrapEl = this.el.wrap();
54337 this.toolbar.container = this.el.insertSibling(false, 'before');
54338 this.toolbar = new Roo.Toolbar(this.toolbar);
54341 // xtype created footer. - not sure if will work as we normally have to render first..
54342 if (this.footer && !this.footer.el && this.footer.xtype) {
54343 if (!this.wrapEl) {
54344 this.wrapEl = this.el.wrap();
54347 this.footer.container = this.wrapEl.createChild();
54349 this.footer = Roo.factory(this.footer, Roo);
54354 this.resizeEl = Roo.get(this.resizeEl, true);
54356 this.resizeEl = this.el;
54358 // handle view.xtype
54366 * Fires when this panel is activated.
54367 * @param {Roo.ContentPanel} this
54371 * @event deactivate
54372 * Fires when this panel is activated.
54373 * @param {Roo.ContentPanel} this
54375 "deactivate" : true,
54379 * Fires when this panel is resized if fitToFrame is true.
54380 * @param {Roo.ContentPanel} this
54381 * @param {Number} width The width after any component adjustments
54382 * @param {Number} height The height after any component adjustments
54388 * Fires when this tab is created
54389 * @param {Roo.ContentPanel} this
54399 if(this.autoScroll){
54400 this.resizeEl.setStyle("overflow", "auto");
54402 // fix randome scrolling
54403 this.el.on('scroll', function() {
54404 Roo.log('fix random scolling');
54405 this.scrollTo('top',0);
54408 content = content || this.content;
54410 this.setContent(content);
54412 if(config && config.url){
54413 this.setUrl(this.url, this.params, this.loadOnce);
54418 Roo.ContentPanel.superclass.constructor.call(this);
54420 if (this.view && typeof(this.view.xtype) != 'undefined') {
54421 this.view.el = this.el.appendChild(document.createElement("div"));
54422 this.view = Roo.factory(this.view);
54423 this.view.render && this.view.render(false, '');
54427 this.fireEvent('render', this);
54430 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54432 setRegion : function(region){
54433 this.region = region;
54435 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54437 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54442 * Returns the toolbar for this Panel if one was configured.
54443 * @return {Roo.Toolbar}
54445 getToolbar : function(){
54446 return this.toolbar;
54449 setActiveState : function(active){
54450 this.active = active;
54452 this.fireEvent("deactivate", this);
54454 this.fireEvent("activate", this);
54458 * Updates this panel's element
54459 * @param {String} content The new content
54460 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54462 setContent : function(content, loadScripts){
54463 this.el.update(content, loadScripts);
54466 ignoreResize : function(w, h){
54467 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54470 this.lastSize = {width: w, height: h};
54475 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54476 * @return {Roo.UpdateManager} The UpdateManager
54478 getUpdateManager : function(){
54479 return this.el.getUpdateManager();
54482 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54483 * @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:
54486 url: "your-url.php",
54487 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54488 callback: yourFunction,
54489 scope: yourObject, //(optional scope)
54492 text: "Loading...",
54497 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54498 * 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.
54499 * @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}
54500 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54501 * @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.
54502 * @return {Roo.ContentPanel} this
54505 var um = this.el.getUpdateManager();
54506 um.update.apply(um, arguments);
54512 * 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.
54513 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54514 * @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)
54515 * @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)
54516 * @return {Roo.UpdateManager} The UpdateManager
54518 setUrl : function(url, params, loadOnce){
54519 if(this.refreshDelegate){
54520 this.removeListener("activate", this.refreshDelegate);
54522 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54523 this.on("activate", this.refreshDelegate);
54524 return this.el.getUpdateManager();
54527 _handleRefresh : function(url, params, loadOnce){
54528 if(!loadOnce || !this.loaded){
54529 var updater = this.el.getUpdateManager();
54530 updater.update(url, params, this._setLoaded.createDelegate(this));
54534 _setLoaded : function(){
54535 this.loaded = true;
54539 * Returns this panel's id
54542 getId : function(){
54547 * Returns this panel's element - used by regiosn to add.
54548 * @return {Roo.Element}
54550 getEl : function(){
54551 return this.wrapEl || this.el;
54554 adjustForComponents : function(width, height)
54556 //Roo.log('adjustForComponents ');
54557 if(this.resizeEl != this.el){
54558 width -= this.el.getFrameWidth('lr');
54559 height -= this.el.getFrameWidth('tb');
54562 var te = this.toolbar.getEl();
54563 height -= te.getHeight();
54564 te.setWidth(width);
54567 var te = this.footer.getEl();
54568 //Roo.log("footer:" + te.getHeight());
54570 height -= te.getHeight();
54571 te.setWidth(width);
54575 if(this.adjustments){
54576 width += this.adjustments[0];
54577 height += this.adjustments[1];
54579 return {"width": width, "height": height};
54582 setSize : function(width, height){
54583 if(this.fitToFrame && !this.ignoreResize(width, height)){
54584 if(this.fitContainer && this.resizeEl != this.el){
54585 this.el.setSize(width, height);
54587 var size = this.adjustForComponents(width, height);
54588 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54589 this.fireEvent('resize', this, size.width, size.height);
54594 * Returns this panel's title
54597 getTitle : function(){
54602 * Set this panel's title
54603 * @param {String} title
54605 setTitle : function(title){
54606 this.title = title;
54608 this.region.updatePanelTitle(this, title);
54613 * Returns true is this panel was configured to be closable
54614 * @return {Boolean}
54616 isClosable : function(){
54617 return this.closable;
54620 beforeSlide : function(){
54622 this.resizeEl.clip();
54625 afterSlide : function(){
54627 this.resizeEl.unclip();
54631 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54632 * Will fail silently if the {@link #setUrl} method has not been called.
54633 * This does not activate the panel, just updates its content.
54635 refresh : function(){
54636 if(this.refreshDelegate){
54637 this.loaded = false;
54638 this.refreshDelegate();
54643 * Destroys this panel
54645 destroy : function(){
54646 this.el.removeAllListeners();
54647 var tempEl = document.createElement("span");
54648 tempEl.appendChild(this.el.dom);
54649 tempEl.innerHTML = "";
54655 * form - if the content panel contains a form - this is a reference to it.
54656 * @type {Roo.form.Form}
54660 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54661 * This contains a reference to it.
54667 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54677 * @param {Object} cfg Xtype definition of item to add.
54680 addxtype : function(cfg) {
54682 if (cfg.xtype.match(/^Form$/)) {
54685 //if (this.footer) {
54686 // el = this.footer.container.insertSibling(false, 'before');
54688 el = this.el.createChild();
54691 this.form = new Roo.form.Form(cfg);
54694 if ( this.form.allItems.length) {
54695 this.form.render(el.dom);
54699 // should only have one of theses..
54700 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54701 // views.. should not be just added - used named prop 'view''
54703 cfg.el = this.el.appendChild(document.createElement("div"));
54706 var ret = new Roo.factory(cfg);
54708 ret.render && ret.render(false, ''); // render blank..
54717 * @class Roo.GridPanel
54718 * @extends Roo.ContentPanel
54720 * Create a new GridPanel.
54721 * @param {Roo.grid.Grid} grid The grid for this panel
54722 * @param {String/Object} config A string to set only the panel's title, or a config object
54724 Roo.GridPanel = function(grid, config){
54727 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54728 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54730 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54732 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54735 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54737 // xtype created footer. - not sure if will work as we normally have to render first..
54738 if (this.footer && !this.footer.el && this.footer.xtype) {
54740 this.footer.container = this.grid.getView().getFooterPanel(true);
54741 this.footer.dataSource = this.grid.dataSource;
54742 this.footer = Roo.factory(this.footer, Roo);
54746 grid.monitorWindowResize = false; // turn off autosizing
54747 grid.autoHeight = false;
54748 grid.autoWidth = false;
54750 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54753 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54754 getId : function(){
54755 return this.grid.id;
54759 * Returns the grid for this panel
54760 * @return {Roo.grid.Grid}
54762 getGrid : function(){
54766 setSize : function(width, height){
54767 if(!this.ignoreResize(width, height)){
54768 var grid = this.grid;
54769 var size = this.adjustForComponents(width, height);
54770 grid.getGridEl().setSize(size.width, size.height);
54775 beforeSlide : function(){
54776 this.grid.getView().scroller.clip();
54779 afterSlide : function(){
54780 this.grid.getView().scroller.unclip();
54783 destroy : function(){
54784 this.grid.destroy();
54786 Roo.GridPanel.superclass.destroy.call(this);
54792 * @class Roo.NestedLayoutPanel
54793 * @extends Roo.ContentPanel
54795 * Create a new NestedLayoutPanel.
54798 * @param {Roo.BorderLayout} layout The layout for this panel
54799 * @param {String/Object} config A string to set only the title or a config object
54801 Roo.NestedLayoutPanel = function(layout, config)
54803 // construct with only one argument..
54804 /* FIXME - implement nicer consturctors
54805 if (layout.layout) {
54807 layout = config.layout;
54808 delete config.layout;
54810 if (layout.xtype && !layout.getEl) {
54811 // then layout needs constructing..
54812 layout = Roo.factory(layout, Roo);
54817 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54819 layout.monitorWindowResize = false; // turn off autosizing
54820 this.layout = layout;
54821 this.layout.getEl().addClass("x-layout-nested-layout");
54828 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
54830 setSize : function(width, height){
54831 if(!this.ignoreResize(width, height)){
54832 var size = this.adjustForComponents(width, height);
54833 var el = this.layout.getEl();
54834 el.setSize(size.width, size.height);
54835 var touch = el.dom.offsetWidth;
54836 this.layout.layout();
54837 // ie requires a double layout on the first pass
54838 if(Roo.isIE && !this.initialized){
54839 this.initialized = true;
54840 this.layout.layout();
54845 // activate all subpanels if not currently active..
54847 setActiveState : function(active){
54848 this.active = active;
54850 this.fireEvent("deactivate", this);
54854 this.fireEvent("activate", this);
54855 // not sure if this should happen before or after..
54856 if (!this.layout) {
54857 return; // should not happen..
54860 for (var r in this.layout.regions) {
54861 reg = this.layout.getRegion(r);
54862 if (reg.getActivePanel()) {
54863 //reg.showPanel(reg.getActivePanel()); // force it to activate..
54864 reg.setActivePanel(reg.getActivePanel());
54867 if (!reg.panels.length) {
54870 reg.showPanel(reg.getPanel(0));
54879 * Returns the nested BorderLayout for this panel
54880 * @return {Roo.BorderLayout}
54882 getLayout : function(){
54883 return this.layout;
54887 * Adds a xtype elements to the layout of the nested panel
54891 xtype : 'ContentPanel',
54898 xtype : 'NestedLayoutPanel',
54904 items : [ ... list of content panels or nested layout panels.. ]
54908 * @param {Object} cfg Xtype definition of item to add.
54910 addxtype : function(cfg) {
54911 return this.layout.addxtype(cfg);
54916 Roo.ScrollPanel = function(el, config, content){
54917 config = config || {};
54918 config.fitToFrame = true;
54919 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
54921 this.el.dom.style.overflow = "hidden";
54922 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
54923 this.el.removeClass("x-layout-inactive-content");
54924 this.el.on("mousewheel", this.onWheel, this);
54926 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
54927 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
54928 up.unselectable(); down.unselectable();
54929 up.on("click", this.scrollUp, this);
54930 down.on("click", this.scrollDown, this);
54931 up.addClassOnOver("x-scroller-btn-over");
54932 down.addClassOnOver("x-scroller-btn-over");
54933 up.addClassOnClick("x-scroller-btn-click");
54934 down.addClassOnClick("x-scroller-btn-click");
54935 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
54937 this.resizeEl = this.el;
54938 this.el = wrap; this.up = up; this.down = down;
54941 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
54943 wheelIncrement : 5,
54944 scrollUp : function(){
54945 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
54948 scrollDown : function(){
54949 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
54952 afterScroll : function(){
54953 var el = this.resizeEl;
54954 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
54955 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54956 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54959 setSize : function(){
54960 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
54961 this.afterScroll();
54964 onWheel : function(e){
54965 var d = e.getWheelDelta();
54966 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
54967 this.afterScroll();
54971 setContent : function(content, loadScripts){
54972 this.resizeEl.update(content, loadScripts);
54986 * @class Roo.TreePanel
54987 * @extends Roo.ContentPanel
54989 * Create a new TreePanel. - defaults to fit/scoll contents.
54990 * @param {String/Object} config A string to set only the panel's title, or a config object
54991 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
54993 Roo.TreePanel = function(config){
54994 var el = config.el;
54995 var tree = config.tree;
54996 delete config.tree;
54997 delete config.el; // hopefull!
54999 // wrapper for IE7 strict & safari scroll issue
55001 var treeEl = el.createChild();
55002 config.resizeEl = treeEl;
55006 Roo.TreePanel.superclass.constructor.call(this, el, config);
55009 this.tree = new Roo.tree.TreePanel(treeEl , tree);
55010 //console.log(tree);
55011 this.on('activate', function()
55013 if (this.tree.rendered) {
55016 //console.log('render tree');
55017 this.tree.render();
55019 // this should not be needed.. - it's actually the 'el' that resizes?
55020 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
55022 //this.on('resize', function (cp, w, h) {
55023 // this.tree.innerCt.setWidth(w);
55024 // this.tree.innerCt.setHeight(h);
55025 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
55032 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
55049 * Ext JS Library 1.1.1
55050 * Copyright(c) 2006-2007, Ext JS, LLC.
55052 * Originally Released Under LGPL - original licence link has changed is not relivant.
55055 * <script type="text/javascript">
55060 * @class Roo.ReaderLayout
55061 * @extends Roo.BorderLayout
55062 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
55063 * center region containing two nested regions (a top one for a list view and one for item preview below),
55064 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
55065 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
55066 * expedites the setup of the overall layout and regions for this common application style.
55069 var reader = new Roo.ReaderLayout();
55070 var CP = Roo.ContentPanel; // shortcut for adding
55072 reader.beginUpdate();
55073 reader.add("north", new CP("north", "North"));
55074 reader.add("west", new CP("west", {title: "West"}));
55075 reader.add("east", new CP("east", {title: "East"}));
55077 reader.regions.listView.add(new CP("listView", "List"));
55078 reader.regions.preview.add(new CP("preview", "Preview"));
55079 reader.endUpdate();
55082 * Create a new ReaderLayout
55083 * @param {Object} config Configuration options
55084 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55085 * document.body if omitted)
55087 Roo.ReaderLayout = function(config, renderTo){
55088 var c = config || {size:{}};
55089 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55090 north: c.north !== false ? Roo.apply({
55094 }, c.north) : false,
55095 west: c.west !== false ? Roo.apply({
55103 margins:{left:5,right:0,bottom:5,top:5},
55104 cmargins:{left:5,right:5,bottom:5,top:5}
55105 }, c.west) : false,
55106 east: c.east !== false ? Roo.apply({
55114 margins:{left:0,right:5,bottom:5,top:5},
55115 cmargins:{left:5,right:5,bottom:5,top:5}
55116 }, c.east) : false,
55117 center: Roo.apply({
55118 tabPosition: 'top',
55122 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55126 this.el.addClass('x-reader');
55128 this.beginUpdate();
55130 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55131 south: c.preview !== false ? Roo.apply({
55138 cmargins:{top:5,left:0, right:0, bottom:0}
55139 }, c.preview) : false,
55140 center: Roo.apply({
55146 this.add('center', new Roo.NestedLayoutPanel(inner,
55147 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55151 this.regions.preview = inner.getRegion('south');
55152 this.regions.listView = inner.getRegion('center');
55155 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55157 * Ext JS Library 1.1.1
55158 * Copyright(c) 2006-2007, Ext JS, LLC.
55160 * Originally Released Under LGPL - original licence link has changed is not relivant.
55163 * <script type="text/javascript">
55167 * @class Roo.grid.Grid
55168 * @extends Roo.util.Observable
55169 * This class represents the primary interface of a component based grid control.
55170 * <br><br>Usage:<pre><code>
55171 var grid = new Roo.grid.Grid("my-container-id", {
55174 selModel: mySelectionModel,
55175 autoSizeColumns: true,
55176 monitorWindowResize: false,
55177 trackMouseOver: true
55182 * <b>Common Problems:</b><br/>
55183 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55184 * element will correct this<br/>
55185 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55186 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55187 * are unpredictable.<br/>
55188 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55189 * grid to calculate dimensions/offsets.<br/>
55191 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55192 * The container MUST have some type of size defined for the grid to fill. The container will be
55193 * automatically set to position relative if it isn't already.
55194 * @param {Object} config A config object that sets properties on this grid.
55196 Roo.grid.Grid = function(container, config){
55197 // initialize the container
55198 this.container = Roo.get(container);
55199 this.container.update("");
55200 this.container.setStyle("overflow", "hidden");
55201 this.container.addClass('x-grid-container');
55203 this.id = this.container.id;
55205 Roo.apply(this, config);
55206 // check and correct shorthanded configs
55208 this.dataSource = this.ds;
55212 this.colModel = this.cm;
55216 this.selModel = this.sm;
55220 if (this.selModel) {
55221 this.selModel = Roo.factory(this.selModel, Roo.grid);
55222 this.sm = this.selModel;
55223 this.sm.xmodule = this.xmodule || false;
55225 if (typeof(this.colModel.config) == 'undefined') {
55226 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55227 this.cm = this.colModel;
55228 this.cm.xmodule = this.xmodule || false;
55230 if (this.dataSource) {
55231 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55232 this.ds = this.dataSource;
55233 this.ds.xmodule = this.xmodule || false;
55240 this.container.setWidth(this.width);
55244 this.container.setHeight(this.height);
55251 * The raw click event for the entire grid.
55252 * @param {Roo.EventObject} e
55257 * The raw dblclick event for the entire grid.
55258 * @param {Roo.EventObject} e
55262 * @event contextmenu
55263 * The raw contextmenu event for the entire grid.
55264 * @param {Roo.EventObject} e
55266 "contextmenu" : true,
55269 * The raw mousedown event for the entire grid.
55270 * @param {Roo.EventObject} e
55272 "mousedown" : true,
55275 * The raw mouseup event for the entire grid.
55276 * @param {Roo.EventObject} e
55281 * The raw mouseover event for the entire grid.
55282 * @param {Roo.EventObject} e
55284 "mouseover" : true,
55287 * The raw mouseout event for the entire grid.
55288 * @param {Roo.EventObject} e
55293 * The raw keypress event for the entire grid.
55294 * @param {Roo.EventObject} e
55299 * The raw keydown event for the entire grid.
55300 * @param {Roo.EventObject} e
55308 * Fires when a cell is clicked
55309 * @param {Grid} this
55310 * @param {Number} rowIndex
55311 * @param {Number} columnIndex
55312 * @param {Roo.EventObject} e
55314 "cellclick" : true,
55316 * @event celldblclick
55317 * Fires when a cell is double clicked
55318 * @param {Grid} this
55319 * @param {Number} rowIndex
55320 * @param {Number} columnIndex
55321 * @param {Roo.EventObject} e
55323 "celldblclick" : true,
55326 * Fires when a row is clicked
55327 * @param {Grid} this
55328 * @param {Number} rowIndex
55329 * @param {Roo.EventObject} e
55333 * @event rowdblclick
55334 * Fires when a row is double clicked
55335 * @param {Grid} this
55336 * @param {Number} rowIndex
55337 * @param {Roo.EventObject} e
55339 "rowdblclick" : true,
55341 * @event headerclick
55342 * Fires when a header is clicked
55343 * @param {Grid} this
55344 * @param {Number} columnIndex
55345 * @param {Roo.EventObject} e
55347 "headerclick" : true,
55349 * @event headerdblclick
55350 * Fires when a header cell is double clicked
55351 * @param {Grid} this
55352 * @param {Number} columnIndex
55353 * @param {Roo.EventObject} e
55355 "headerdblclick" : true,
55357 * @event rowcontextmenu
55358 * Fires when a row is right clicked
55359 * @param {Grid} this
55360 * @param {Number} rowIndex
55361 * @param {Roo.EventObject} e
55363 "rowcontextmenu" : true,
55365 * @event cellcontextmenu
55366 * Fires when a cell is right clicked
55367 * @param {Grid} this
55368 * @param {Number} rowIndex
55369 * @param {Number} cellIndex
55370 * @param {Roo.EventObject} e
55372 "cellcontextmenu" : true,
55374 * @event headercontextmenu
55375 * Fires when a header is right clicked
55376 * @param {Grid} this
55377 * @param {Number} columnIndex
55378 * @param {Roo.EventObject} e
55380 "headercontextmenu" : true,
55382 * @event bodyscroll
55383 * Fires when the body element is scrolled
55384 * @param {Number} scrollLeft
55385 * @param {Number} scrollTop
55387 "bodyscroll" : true,
55389 * @event columnresize
55390 * Fires when the user resizes a column
55391 * @param {Number} columnIndex
55392 * @param {Number} newSize
55394 "columnresize" : true,
55396 * @event columnmove
55397 * Fires when the user moves a column
55398 * @param {Number} oldIndex
55399 * @param {Number} newIndex
55401 "columnmove" : true,
55404 * Fires when row(s) start being dragged
55405 * @param {Grid} this
55406 * @param {Roo.GridDD} dd The drag drop object
55407 * @param {event} e The raw browser event
55409 "startdrag" : true,
55412 * Fires when a drag operation is complete
55413 * @param {Grid} this
55414 * @param {Roo.GridDD} dd The drag drop object
55415 * @param {event} e The raw browser event
55420 * Fires when dragged row(s) are dropped on a valid DD target
55421 * @param {Grid} this
55422 * @param {Roo.GridDD} dd The drag drop object
55423 * @param {String} targetId The target drag drop object
55424 * @param {event} e The raw browser event
55429 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55430 * @param {Grid} this
55431 * @param {Roo.GridDD} dd The drag drop object
55432 * @param {String} targetId The target drag drop object
55433 * @param {event} e The raw browser event
55438 * Fires when the dragged row(s) first cross another DD target while being dragged
55439 * @param {Grid} this
55440 * @param {Roo.GridDD} dd The drag drop object
55441 * @param {String} targetId The target drag drop object
55442 * @param {event} e The raw browser event
55444 "dragenter" : true,
55447 * Fires when the dragged row(s) leave another DD target while being dragged
55448 * @param {Grid} this
55449 * @param {Roo.GridDD} dd The drag drop object
55450 * @param {String} targetId The target drag drop object
55451 * @param {event} e The raw browser event
55456 * Fires when a row is rendered, so you can change add a style to it.
55457 * @param {GridView} gridview The grid view
55458 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55464 * Fires when the grid is rendered
55465 * @param {Grid} grid
55470 Roo.grid.Grid.superclass.constructor.call(this);
55472 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55475 * @cfg {String} ddGroup - drag drop group.
55478 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
55482 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55484 minColumnWidth : 25,
55487 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55488 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55489 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55491 autoSizeColumns : false,
55494 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55496 autoSizeHeaders : true,
55499 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55501 monitorWindowResize : true,
55504 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55505 * rows measured to get a columns size. Default is 0 (all rows).
55507 maxRowsToMeasure : 0,
55510 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55512 trackMouseOver : true,
55515 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55518 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
55522 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55524 enableDragDrop : false,
55527 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55529 enableColumnMove : true,
55532 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55534 enableColumnHide : true,
55537 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55539 enableRowHeightSync : false,
55542 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55547 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55549 autoHeight : false,
55552 * @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.
55554 autoExpandColumn : false,
55557 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55560 autoExpandMin : 50,
55563 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55565 autoExpandMax : 1000,
55568 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55573 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55577 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55587 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55588 * of a fixed width. Default is false.
55591 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55596 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55597 * %0 is replaced with the number of selected rows.
55599 ddText : "{0} selected row{1}",
55603 * Called once after all setup has been completed and the grid is ready to be rendered.
55604 * @return {Roo.grid.Grid} this
55606 render : function()
55608 var c = this.container;
55609 // try to detect autoHeight/width mode
55610 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55611 this.autoHeight = true;
55613 var view = this.getView();
55616 c.on("click", this.onClick, this);
55617 c.on("dblclick", this.onDblClick, this);
55618 c.on("contextmenu", this.onContextMenu, this);
55619 c.on("keydown", this.onKeyDown, this);
55621 c.on("touchstart", this.onTouchStart, this);
55624 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55626 this.getSelectionModel().init(this);
55631 this.loadMask = new Roo.LoadMask(this.container,
55632 Roo.apply({store:this.dataSource}, this.loadMask));
55636 if (this.toolbar && this.toolbar.xtype) {
55637 this.toolbar.container = this.getView().getHeaderPanel(true);
55638 this.toolbar = new Roo.Toolbar(this.toolbar);
55640 if (this.footer && this.footer.xtype) {
55641 this.footer.dataSource = this.getDataSource();
55642 this.footer.container = this.getView().getFooterPanel(true);
55643 this.footer = Roo.factory(this.footer, Roo);
55645 if (this.dropTarget && this.dropTarget.xtype) {
55646 delete this.dropTarget.xtype;
55647 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55651 this.rendered = true;
55652 this.fireEvent('render', this);
55657 * Reconfigures the grid to use a different Store and Column Model.
55658 * The View will be bound to the new objects and refreshed.
55659 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55660 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55662 reconfigure : function(dataSource, colModel){
55664 this.loadMask.destroy();
55665 this.loadMask = new Roo.LoadMask(this.container,
55666 Roo.apply({store:dataSource}, this.loadMask));
55668 this.view.bind(dataSource, colModel);
55669 this.dataSource = dataSource;
55670 this.colModel = colModel;
55671 this.view.refresh(true);
55675 * Add's a column, default at the end..
55677 * @param {int} position to add (default end)
55678 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55680 addColumns : function(pos, ar)
55683 for (var i =0;i< ar.length;i++) {
55685 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55686 this.cm.lookup[cfg.id] = cfg;
55690 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55691 pos = this.cm.config.length; //this.cm.config.push(cfg);
55693 pos = Math.max(0,pos);
55696 this.cm.config.splice.apply(this.cm.config, ar);
55700 this.view.generateRules(this.cm);
55701 this.view.refresh(true);
55709 onKeyDown : function(e){
55710 this.fireEvent("keydown", e);
55714 * Destroy this grid.
55715 * @param {Boolean} removeEl True to remove the element
55717 destroy : function(removeEl, keepListeners){
55719 this.loadMask.destroy();
55721 var c = this.container;
55722 c.removeAllListeners();
55723 this.view.destroy();
55724 this.colModel.purgeListeners();
55725 if(!keepListeners){
55726 this.purgeListeners();
55729 if(removeEl === true){
55735 processEvent : function(name, e){
55736 // does this fire select???
55737 //Roo.log('grid:processEvent ' + name);
55739 if (name != 'touchstart' ) {
55740 this.fireEvent(name, e);
55743 var t = e.getTarget();
55745 var header = v.findHeaderIndex(t);
55746 if(header !== false){
55747 var ename = name == 'touchstart' ? 'click' : name;
55749 this.fireEvent("header" + ename, this, header, e);
55751 var row = v.findRowIndex(t);
55752 var cell = v.findCellIndex(t);
55753 if (name == 'touchstart') {
55754 // first touch is always a click.
55755 // hopefull this happens after selection is updated.?
55758 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55759 var cs = this.selModel.getSelectedCell();
55760 if (row == cs[0] && cell == cs[1]){
55764 if (typeof(this.selModel.getSelections) != 'undefined') {
55765 var cs = this.selModel.getSelections();
55766 var ds = this.dataSource;
55767 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55778 this.fireEvent("row" + name, this, row, e);
55779 if(cell !== false){
55780 this.fireEvent("cell" + name, this, row, cell, e);
55787 onClick : function(e){
55788 this.processEvent("click", e);
55791 onTouchStart : function(e){
55792 this.processEvent("touchstart", e);
55796 onContextMenu : function(e, t){
55797 this.processEvent("contextmenu", e);
55801 onDblClick : function(e){
55802 this.processEvent("dblclick", e);
55806 walkCells : function(row, col, step, fn, scope){
55807 var cm = this.colModel, clen = cm.getColumnCount();
55808 var ds = this.dataSource, rlen = ds.getCount(), first = true;
55820 if(fn.call(scope || this, row, col, cm) === true){
55838 if(fn.call(scope || this, row, col, cm) === true){
55850 getSelections : function(){
55851 return this.selModel.getSelections();
55855 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
55856 * but if manual update is required this method will initiate it.
55858 autoSize : function(){
55860 this.view.layout();
55861 if(this.view.adjustForScroll){
55862 this.view.adjustForScroll();
55868 * Returns the grid's underlying element.
55869 * @return {Element} The element
55871 getGridEl : function(){
55872 return this.container;
55875 // private for compatibility, overridden by editor grid
55876 stopEditing : function(){},
55879 * Returns the grid's SelectionModel.
55880 * @return {SelectionModel}
55882 getSelectionModel : function(){
55883 if(!this.selModel){
55884 this.selModel = new Roo.grid.RowSelectionModel();
55886 return this.selModel;
55890 * Returns the grid's DataSource.
55891 * @return {DataSource}
55893 getDataSource : function(){
55894 return this.dataSource;
55898 * Returns the grid's ColumnModel.
55899 * @return {ColumnModel}
55901 getColumnModel : function(){
55902 return this.colModel;
55906 * Returns the grid's GridView object.
55907 * @return {GridView}
55909 getView : function(){
55911 this.view = new Roo.grid.GridView(this.viewConfig);
55912 this.relayEvents(this.view, [
55913 "beforerowremoved", "beforerowsinserted",
55914 "beforerefresh", "rowremoved",
55915 "rowsinserted", "rowupdated" ,"refresh"
55921 * Called to get grid's drag proxy text, by default returns this.ddText.
55922 * Override this to put something different in the dragged text.
55925 getDragDropText : function(){
55926 var count = this.selModel.getCount();
55927 return String.format(this.ddText, count, count == 1 ? '' : 's');
55932 * Ext JS Library 1.1.1
55933 * Copyright(c) 2006-2007, Ext JS, LLC.
55935 * Originally Released Under LGPL - original licence link has changed is not relivant.
55938 * <script type="text/javascript">
55941 Roo.grid.AbstractGridView = function(){
55945 "beforerowremoved" : true,
55946 "beforerowsinserted" : true,
55947 "beforerefresh" : true,
55948 "rowremoved" : true,
55949 "rowsinserted" : true,
55950 "rowupdated" : true,
55953 Roo.grid.AbstractGridView.superclass.constructor.call(this);
55956 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
55957 rowClass : "x-grid-row",
55958 cellClass : "x-grid-cell",
55959 tdClass : "x-grid-td",
55960 hdClass : "x-grid-hd",
55961 splitClass : "x-grid-hd-split",
55963 init: function(grid){
55965 var cid = this.grid.getGridEl().id;
55966 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
55967 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
55968 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
55969 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
55972 getColumnRenderers : function(){
55973 var renderers = [];
55974 var cm = this.grid.colModel;
55975 var colCount = cm.getColumnCount();
55976 for(var i = 0; i < colCount; i++){
55977 renderers[i] = cm.getRenderer(i);
55982 getColumnIds : function(){
55984 var cm = this.grid.colModel;
55985 var colCount = cm.getColumnCount();
55986 for(var i = 0; i < colCount; i++){
55987 ids[i] = cm.getColumnId(i);
55992 getDataIndexes : function(){
55993 if(!this.indexMap){
55994 this.indexMap = this.buildIndexMap();
55996 return this.indexMap.colToData;
55999 getColumnIndexByDataIndex : function(dataIndex){
56000 if(!this.indexMap){
56001 this.indexMap = this.buildIndexMap();
56003 return this.indexMap.dataToCol[dataIndex];
56007 * Set a css style for a column dynamically.
56008 * @param {Number} colIndex The index of the column
56009 * @param {String} name The css property name
56010 * @param {String} value The css value
56012 setCSSStyle : function(colIndex, name, value){
56013 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
56014 Roo.util.CSS.updateRule(selector, name, value);
56017 generateRules : function(cm){
56018 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
56019 Roo.util.CSS.removeStyleSheet(rulesId);
56020 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56021 var cid = cm.getColumnId(i);
56022 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
56023 this.tdSelector, cid, " {\n}\n",
56024 this.hdSelector, cid, " {\n}\n",
56025 this.splitSelector, cid, " {\n}\n");
56027 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56031 * Ext JS Library 1.1.1
56032 * Copyright(c) 2006-2007, Ext JS, LLC.
56034 * Originally Released Under LGPL - original licence link has changed is not relivant.
56037 * <script type="text/javascript">
56041 // This is a support class used internally by the Grid components
56042 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
56044 this.view = grid.getView();
56045 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56046 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
56048 this.setHandleElId(Roo.id(hd));
56049 this.setOuterHandleElId(Roo.id(hd2));
56051 this.scroll = false;
56053 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
56055 getDragData : function(e){
56056 var t = Roo.lib.Event.getTarget(e);
56057 var h = this.view.findHeaderCell(t);
56059 return {ddel: h.firstChild, header:h};
56064 onInitDrag : function(e){
56065 this.view.headersDisabled = true;
56066 var clone = this.dragData.ddel.cloneNode(true);
56067 clone.id = Roo.id();
56068 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
56069 this.proxy.update(clone);
56073 afterValidDrop : function(){
56075 setTimeout(function(){
56076 v.headersDisabled = false;
56080 afterInvalidDrop : function(){
56082 setTimeout(function(){
56083 v.headersDisabled = false;
56089 * Ext JS Library 1.1.1
56090 * Copyright(c) 2006-2007, Ext JS, LLC.
56092 * Originally Released Under LGPL - original licence link has changed is not relivant.
56095 * <script type="text/javascript">
56098 // This is a support class used internally by the Grid components
56099 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56101 this.view = grid.getView();
56102 // split the proxies so they don't interfere with mouse events
56103 this.proxyTop = Roo.DomHelper.append(document.body, {
56104 cls:"col-move-top", html:" "
56106 this.proxyBottom = Roo.DomHelper.append(document.body, {
56107 cls:"col-move-bottom", html:" "
56109 this.proxyTop.hide = this.proxyBottom.hide = function(){
56110 this.setLeftTop(-100,-100);
56111 this.setStyle("visibility", "hidden");
56113 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56114 // temporarily disabled
56115 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56116 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56118 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56119 proxyOffsets : [-4, -9],
56120 fly: Roo.Element.fly,
56122 getTargetFromEvent : function(e){
56123 var t = Roo.lib.Event.getTarget(e);
56124 var cindex = this.view.findCellIndex(t);
56125 if(cindex !== false){
56126 return this.view.getHeaderCell(cindex);
56131 nextVisible : function(h){
56132 var v = this.view, cm = this.grid.colModel;
56135 if(!cm.isHidden(v.getCellIndex(h))){
56143 prevVisible : function(h){
56144 var v = this.view, cm = this.grid.colModel;
56147 if(!cm.isHidden(v.getCellIndex(h))){
56155 positionIndicator : function(h, n, e){
56156 var x = Roo.lib.Event.getPageX(e);
56157 var r = Roo.lib.Dom.getRegion(n.firstChild);
56158 var px, pt, py = r.top + this.proxyOffsets[1];
56159 if((r.right - x) <= (r.right-r.left)/2){
56160 px = r.right+this.view.borderWidth;
56166 var oldIndex = this.view.getCellIndex(h);
56167 var newIndex = this.view.getCellIndex(n);
56169 if(this.grid.colModel.isFixed(newIndex)){
56173 var locked = this.grid.colModel.isLocked(newIndex);
56178 if(oldIndex < newIndex){
56181 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56184 px += this.proxyOffsets[0];
56185 this.proxyTop.setLeftTop(px, py);
56186 this.proxyTop.show();
56187 if(!this.bottomOffset){
56188 this.bottomOffset = this.view.mainHd.getHeight();
56190 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56191 this.proxyBottom.show();
56195 onNodeEnter : function(n, dd, e, data){
56196 if(data.header != n){
56197 this.positionIndicator(data.header, n, e);
56201 onNodeOver : function(n, dd, e, data){
56202 var result = false;
56203 if(data.header != n){
56204 result = this.positionIndicator(data.header, n, e);
56207 this.proxyTop.hide();
56208 this.proxyBottom.hide();
56210 return result ? this.dropAllowed : this.dropNotAllowed;
56213 onNodeOut : function(n, dd, e, data){
56214 this.proxyTop.hide();
56215 this.proxyBottom.hide();
56218 onNodeDrop : function(n, dd, e, data){
56219 var h = data.header;
56221 var cm = this.grid.colModel;
56222 var x = Roo.lib.Event.getPageX(e);
56223 var r = Roo.lib.Dom.getRegion(n.firstChild);
56224 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56225 var oldIndex = this.view.getCellIndex(h);
56226 var newIndex = this.view.getCellIndex(n);
56227 var locked = cm.isLocked(newIndex);
56231 if(oldIndex < newIndex){
56234 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56237 cm.setLocked(oldIndex, locked, true);
56238 cm.moveColumn(oldIndex, newIndex);
56239 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56247 * Ext JS Library 1.1.1
56248 * Copyright(c) 2006-2007, Ext JS, LLC.
56250 * Originally Released Under LGPL - original licence link has changed is not relivant.
56253 * <script type="text/javascript">
56257 * @class Roo.grid.GridView
56258 * @extends Roo.util.Observable
56261 * @param {Object} config
56263 Roo.grid.GridView = function(config){
56264 Roo.grid.GridView.superclass.constructor.call(this);
56267 Roo.apply(this, config);
56270 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56272 unselectable : 'unselectable="on"',
56273 unselectableCls : 'x-unselectable',
56276 rowClass : "x-grid-row",
56278 cellClass : "x-grid-col",
56280 tdClass : "x-grid-td",
56282 hdClass : "x-grid-hd",
56284 splitClass : "x-grid-split",
56286 sortClasses : ["sort-asc", "sort-desc"],
56288 enableMoveAnim : false,
56292 dh : Roo.DomHelper,
56294 fly : Roo.Element.fly,
56296 css : Roo.util.CSS,
56302 scrollIncrement : 22,
56304 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56306 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56308 bind : function(ds, cm){
56310 this.ds.un("load", this.onLoad, this);
56311 this.ds.un("datachanged", this.onDataChange, this);
56312 this.ds.un("add", this.onAdd, this);
56313 this.ds.un("remove", this.onRemove, this);
56314 this.ds.un("update", this.onUpdate, this);
56315 this.ds.un("clear", this.onClear, this);
56318 ds.on("load", this.onLoad, this);
56319 ds.on("datachanged", this.onDataChange, this);
56320 ds.on("add", this.onAdd, this);
56321 ds.on("remove", this.onRemove, this);
56322 ds.on("update", this.onUpdate, this);
56323 ds.on("clear", this.onClear, this);
56328 this.cm.un("widthchange", this.onColWidthChange, this);
56329 this.cm.un("headerchange", this.onHeaderChange, this);
56330 this.cm.un("hiddenchange", this.onHiddenChange, this);
56331 this.cm.un("columnmoved", this.onColumnMove, this);
56332 this.cm.un("columnlockchange", this.onColumnLock, this);
56335 this.generateRules(cm);
56336 cm.on("widthchange", this.onColWidthChange, this);
56337 cm.on("headerchange", this.onHeaderChange, this);
56338 cm.on("hiddenchange", this.onHiddenChange, this);
56339 cm.on("columnmoved", this.onColumnMove, this);
56340 cm.on("columnlockchange", this.onColumnLock, this);
56345 init: function(grid){
56346 Roo.grid.GridView.superclass.init.call(this, grid);
56348 this.bind(grid.dataSource, grid.colModel);
56350 grid.on("headerclick", this.handleHeaderClick, this);
56352 if(grid.trackMouseOver){
56353 grid.on("mouseover", this.onRowOver, this);
56354 grid.on("mouseout", this.onRowOut, this);
56356 grid.cancelTextSelection = function(){};
56357 this.gridId = grid.id;
56359 var tpls = this.templates || {};
56362 tpls.master = new Roo.Template(
56363 '<div class="x-grid" hidefocus="true">',
56364 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56365 '<div class="x-grid-topbar"></div>',
56366 '<div class="x-grid-scroller"><div></div></div>',
56367 '<div class="x-grid-locked">',
56368 '<div class="x-grid-header">{lockedHeader}</div>',
56369 '<div class="x-grid-body">{lockedBody}</div>',
56371 '<div class="x-grid-viewport">',
56372 '<div class="x-grid-header">{header}</div>',
56373 '<div class="x-grid-body">{body}</div>',
56375 '<div class="x-grid-bottombar"></div>',
56377 '<div class="x-grid-resize-proxy"> </div>',
56380 tpls.master.disableformats = true;
56384 tpls.header = new Roo.Template(
56385 '<table border="0" cellspacing="0" cellpadding="0">',
56386 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56389 tpls.header.disableformats = true;
56391 tpls.header.compile();
56394 tpls.hcell = new Roo.Template(
56395 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56396 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56399 tpls.hcell.disableFormats = true;
56401 tpls.hcell.compile();
56404 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56405 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56406 tpls.hsplit.disableFormats = true;
56408 tpls.hsplit.compile();
56411 tpls.body = new Roo.Template(
56412 '<table border="0" cellspacing="0" cellpadding="0">',
56413 "<tbody>{rows}</tbody>",
56416 tpls.body.disableFormats = true;
56418 tpls.body.compile();
56421 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56422 tpls.row.disableFormats = true;
56424 tpls.row.compile();
56427 tpls.cell = new Roo.Template(
56428 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56429 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56430 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56433 tpls.cell.disableFormats = true;
56435 tpls.cell.compile();
56437 this.templates = tpls;
56440 // remap these for backwards compat
56441 onColWidthChange : function(){
56442 this.updateColumns.apply(this, arguments);
56444 onHeaderChange : function(){
56445 this.updateHeaders.apply(this, arguments);
56447 onHiddenChange : function(){
56448 this.handleHiddenChange.apply(this, arguments);
56450 onColumnMove : function(){
56451 this.handleColumnMove.apply(this, arguments);
56453 onColumnLock : function(){
56454 this.handleLockChange.apply(this, arguments);
56457 onDataChange : function(){
56459 this.updateHeaderSortState();
56462 onClear : function(){
56466 onUpdate : function(ds, record){
56467 this.refreshRow(record);
56470 refreshRow : function(record){
56471 var ds = this.ds, index;
56472 if(typeof record == 'number'){
56474 record = ds.getAt(index);
56476 index = ds.indexOf(record);
56478 this.insertRows(ds, index, index, true);
56479 this.onRemove(ds, record, index+1, true);
56480 this.syncRowHeights(index, index);
56482 this.fireEvent("rowupdated", this, index, record);
56485 onAdd : function(ds, records, index){
56486 this.insertRows(ds, index, index + (records.length-1));
56489 onRemove : function(ds, record, index, isUpdate){
56490 if(isUpdate !== true){
56491 this.fireEvent("beforerowremoved", this, index, record);
56493 var bt = this.getBodyTable(), lt = this.getLockedTable();
56494 if(bt.rows[index]){
56495 bt.firstChild.removeChild(bt.rows[index]);
56497 if(lt.rows[index]){
56498 lt.firstChild.removeChild(lt.rows[index]);
56500 if(isUpdate !== true){
56501 this.stripeRows(index);
56502 this.syncRowHeights(index, index);
56504 this.fireEvent("rowremoved", this, index, record);
56508 onLoad : function(){
56509 this.scrollToTop();
56513 * Scrolls the grid to the top
56515 scrollToTop : function(){
56517 this.scroller.dom.scrollTop = 0;
56523 * Gets a panel in the header of the grid that can be used for toolbars etc.
56524 * After modifying the contents of this panel a call to grid.autoSize() may be
56525 * required to register any changes in size.
56526 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56527 * @return Roo.Element
56529 getHeaderPanel : function(doShow){
56531 this.headerPanel.show();
56533 return this.headerPanel;
56537 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56538 * After modifying the contents of this panel a call to grid.autoSize() may be
56539 * required to register any changes in size.
56540 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56541 * @return Roo.Element
56543 getFooterPanel : function(doShow){
56545 this.footerPanel.show();
56547 return this.footerPanel;
56550 initElements : function(){
56551 var E = Roo.Element;
56552 var el = this.grid.getGridEl().dom.firstChild;
56553 var cs = el.childNodes;
56555 this.el = new E(el);
56557 this.focusEl = new E(el.firstChild);
56558 this.focusEl.swallowEvent("click", true);
56560 this.headerPanel = new E(cs[1]);
56561 this.headerPanel.enableDisplayMode("block");
56563 this.scroller = new E(cs[2]);
56564 this.scrollSizer = new E(this.scroller.dom.firstChild);
56566 this.lockedWrap = new E(cs[3]);
56567 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56568 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56570 this.mainWrap = new E(cs[4]);
56571 this.mainHd = new E(this.mainWrap.dom.firstChild);
56572 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56574 this.footerPanel = new E(cs[5]);
56575 this.footerPanel.enableDisplayMode("block");
56577 this.resizeProxy = new E(cs[6]);
56579 this.headerSelector = String.format(
56580 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56581 this.lockedHd.id, this.mainHd.id
56584 this.splitterSelector = String.format(
56585 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56586 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56589 idToCssName : function(s)
56591 return s.replace(/[^a-z0-9]+/ig, '-');
56594 getHeaderCell : function(index){
56595 return Roo.DomQuery.select(this.headerSelector)[index];
56598 getHeaderCellMeasure : function(index){
56599 return this.getHeaderCell(index).firstChild;
56602 getHeaderCellText : function(index){
56603 return this.getHeaderCell(index).firstChild.firstChild;
56606 getLockedTable : function(){
56607 return this.lockedBody.dom.firstChild;
56610 getBodyTable : function(){
56611 return this.mainBody.dom.firstChild;
56614 getLockedRow : function(index){
56615 return this.getLockedTable().rows[index];
56618 getRow : function(index){
56619 return this.getBodyTable().rows[index];
56622 getRowComposite : function(index){
56624 this.rowEl = new Roo.CompositeElementLite();
56626 var els = [], lrow, mrow;
56627 if(lrow = this.getLockedRow(index)){
56630 if(mrow = this.getRow(index)){
56633 this.rowEl.elements = els;
56637 * Gets the 'td' of the cell
56639 * @param {Integer} rowIndex row to select
56640 * @param {Integer} colIndex column to select
56644 getCell : function(rowIndex, colIndex){
56645 var locked = this.cm.getLockedCount();
56647 if(colIndex < locked){
56648 source = this.lockedBody.dom.firstChild;
56650 source = this.mainBody.dom.firstChild;
56651 colIndex -= locked;
56653 return source.rows[rowIndex].childNodes[colIndex];
56656 getCellText : function(rowIndex, colIndex){
56657 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56660 getCellBox : function(cell){
56661 var b = this.fly(cell).getBox();
56662 if(Roo.isOpera){ // opera fails to report the Y
56663 b.y = cell.offsetTop + this.mainBody.getY();
56668 getCellIndex : function(cell){
56669 var id = String(cell.className).match(this.cellRE);
56671 return parseInt(id[1], 10);
56676 findHeaderIndex : function(n){
56677 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56678 return r ? this.getCellIndex(r) : false;
56681 findHeaderCell : function(n){
56682 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56683 return r ? r : false;
56686 findRowIndex : function(n){
56690 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56691 return r ? r.rowIndex : false;
56694 findCellIndex : function(node){
56695 var stop = this.el.dom;
56696 while(node && node != stop){
56697 if(this.findRE.test(node.className)){
56698 return this.getCellIndex(node);
56700 node = node.parentNode;
56705 getColumnId : function(index){
56706 return this.cm.getColumnId(index);
56709 getSplitters : function()
56711 if(this.splitterSelector){
56712 return Roo.DomQuery.select(this.splitterSelector);
56718 getSplitter : function(index){
56719 return this.getSplitters()[index];
56722 onRowOver : function(e, t){
56724 if((row = this.findRowIndex(t)) !== false){
56725 this.getRowComposite(row).addClass("x-grid-row-over");
56729 onRowOut : function(e, t){
56731 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56732 this.getRowComposite(row).removeClass("x-grid-row-over");
56736 renderHeaders : function(){
56738 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56739 var cb = [], lb = [], sb = [], lsb = [], p = {};
56740 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56741 p.cellId = "x-grid-hd-0-" + i;
56742 p.splitId = "x-grid-csplit-0-" + i;
56743 p.id = cm.getColumnId(i);
56744 p.value = cm.getColumnHeader(i) || "";
56745 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56746 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56747 if(!cm.isLocked(i)){
56748 cb[cb.length] = ct.apply(p);
56749 sb[sb.length] = st.apply(p);
56751 lb[lb.length] = ct.apply(p);
56752 lsb[lsb.length] = st.apply(p);
56755 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56756 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56759 updateHeaders : function(){
56760 var html = this.renderHeaders();
56761 this.lockedHd.update(html[0]);
56762 this.mainHd.update(html[1]);
56766 * Focuses the specified row.
56767 * @param {Number} row The row index
56769 focusRow : function(row)
56771 //Roo.log('GridView.focusRow');
56772 var x = this.scroller.dom.scrollLeft;
56773 this.focusCell(row, 0, false);
56774 this.scroller.dom.scrollLeft = x;
56778 * Focuses the specified cell.
56779 * @param {Number} row The row index
56780 * @param {Number} col The column index
56781 * @param {Boolean} hscroll false to disable horizontal scrolling
56783 focusCell : function(row, col, hscroll)
56785 //Roo.log('GridView.focusCell');
56786 var el = this.ensureVisible(row, col, hscroll);
56787 this.focusEl.alignTo(el, "tl-tl");
56789 this.focusEl.focus();
56791 this.focusEl.focus.defer(1, this.focusEl);
56796 * Scrolls the specified cell into view
56797 * @param {Number} row The row index
56798 * @param {Number} col The column index
56799 * @param {Boolean} hscroll false to disable horizontal scrolling
56801 ensureVisible : function(row, col, hscroll)
56803 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56804 //return null; //disable for testing.
56805 if(typeof row != "number"){
56806 row = row.rowIndex;
56808 if(row < 0 && row >= this.ds.getCount()){
56811 col = (col !== undefined ? col : 0);
56812 var cm = this.grid.colModel;
56813 while(cm.isHidden(col)){
56817 var el = this.getCell(row, col);
56821 var c = this.scroller.dom;
56823 var ctop = parseInt(el.offsetTop, 10);
56824 var cleft = parseInt(el.offsetLeft, 10);
56825 var cbot = ctop + el.offsetHeight;
56826 var cright = cleft + el.offsetWidth;
56828 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
56829 var stop = parseInt(c.scrollTop, 10);
56830 var sleft = parseInt(c.scrollLeft, 10);
56831 var sbot = stop + ch;
56832 var sright = sleft + c.clientWidth;
56834 Roo.log('GridView.ensureVisible:' +
56836 ' c.clientHeight:' + c.clientHeight +
56837 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
56845 c.scrollTop = ctop;
56846 //Roo.log("set scrolltop to ctop DISABLE?");
56847 }else if(cbot > sbot){
56848 //Roo.log("set scrolltop to cbot-ch");
56849 c.scrollTop = cbot-ch;
56852 if(hscroll !== false){
56854 c.scrollLeft = cleft;
56855 }else if(cright > sright){
56856 c.scrollLeft = cright-c.clientWidth;
56863 updateColumns : function(){
56864 this.grid.stopEditing();
56865 var cm = this.grid.colModel, colIds = this.getColumnIds();
56866 //var totalWidth = cm.getTotalWidth();
56868 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56869 //if(cm.isHidden(i)) continue;
56870 var w = cm.getColumnWidth(i);
56871 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56872 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56874 this.updateSplitters();
56877 generateRules : function(cm){
56878 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
56879 Roo.util.CSS.removeStyleSheet(rulesId);
56880 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56881 var cid = cm.getColumnId(i);
56883 if(cm.config[i].align){
56884 align = 'text-align:'+cm.config[i].align+';';
56887 if(cm.isHidden(i)){
56888 hidden = 'display:none;';
56890 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
56892 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
56893 this.hdSelector, cid, " {\n", align, width, "}\n",
56894 this.tdSelector, cid, " {\n",hidden,"\n}\n",
56895 this.splitSelector, cid, " {\n", hidden , "\n}\n");
56897 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56900 updateSplitters : function(){
56901 var cm = this.cm, s = this.getSplitters();
56902 if(s){ // splitters not created yet
56903 var pos = 0, locked = true;
56904 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56905 if(cm.isHidden(i)) {
56908 var w = cm.getColumnWidth(i); // make sure it's a number
56909 if(!cm.isLocked(i) && locked){
56914 s[i].style.left = (pos-this.splitOffset) + "px";
56919 handleHiddenChange : function(colModel, colIndex, hidden){
56921 this.hideColumn(colIndex);
56923 this.unhideColumn(colIndex);
56927 hideColumn : function(colIndex){
56928 var cid = this.getColumnId(colIndex);
56929 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
56930 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
56932 this.updateHeaders();
56934 this.updateSplitters();
56938 unhideColumn : function(colIndex){
56939 var cid = this.getColumnId(colIndex);
56940 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
56941 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
56944 this.updateHeaders();
56946 this.updateSplitters();
56950 insertRows : function(dm, firstRow, lastRow, isUpdate){
56951 if(firstRow == 0 && lastRow == dm.getCount()-1){
56955 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
56957 var s = this.getScrollState();
56958 var markup = this.renderRows(firstRow, lastRow);
56959 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
56960 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
56961 this.restoreScroll(s);
56963 this.fireEvent("rowsinserted", this, firstRow, lastRow);
56964 this.syncRowHeights(firstRow, lastRow);
56965 this.stripeRows(firstRow);
56971 bufferRows : function(markup, target, index){
56972 var before = null, trows = target.rows, tbody = target.tBodies[0];
56973 if(index < trows.length){
56974 before = trows[index];
56976 var b = document.createElement("div");
56977 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
56978 var rows = b.firstChild.rows;
56979 for(var i = 0, len = rows.length; i < len; i++){
56981 tbody.insertBefore(rows[0], before);
56983 tbody.appendChild(rows[0]);
56990 deleteRows : function(dm, firstRow, lastRow){
56991 if(dm.getRowCount()<1){
56992 this.fireEvent("beforerefresh", this);
56993 this.mainBody.update("");
56994 this.lockedBody.update("");
56995 this.fireEvent("refresh", this);
56997 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
56998 var bt = this.getBodyTable();
56999 var tbody = bt.firstChild;
57000 var rows = bt.rows;
57001 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
57002 tbody.removeChild(rows[firstRow]);
57004 this.stripeRows(firstRow);
57005 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
57009 updateRows : function(dataSource, firstRow, lastRow){
57010 var s = this.getScrollState();
57012 this.restoreScroll(s);
57015 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
57019 this.updateHeaderSortState();
57022 getScrollState : function(){
57024 var sb = this.scroller.dom;
57025 return {left: sb.scrollLeft, top: sb.scrollTop};
57028 stripeRows : function(startRow){
57029 if(!this.grid.stripeRows || this.ds.getCount() < 1){
57032 startRow = startRow || 0;
57033 var rows = this.getBodyTable().rows;
57034 var lrows = this.getLockedTable().rows;
57035 var cls = ' x-grid-row-alt ';
57036 for(var i = startRow, len = rows.length; i < len; i++){
57037 var row = rows[i], lrow = lrows[i];
57038 var isAlt = ((i+1) % 2 == 0);
57039 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
57040 if(isAlt == hasAlt){
57044 row.className += " x-grid-row-alt";
57046 row.className = row.className.replace("x-grid-row-alt", "");
57049 lrow.className = row.className;
57054 restoreScroll : function(state){
57055 //Roo.log('GridView.restoreScroll');
57056 var sb = this.scroller.dom;
57057 sb.scrollLeft = state.left;
57058 sb.scrollTop = state.top;
57062 syncScroll : function(){
57063 //Roo.log('GridView.syncScroll');
57064 var sb = this.scroller.dom;
57065 var sh = this.mainHd.dom;
57066 var bs = this.mainBody.dom;
57067 var lv = this.lockedBody.dom;
57068 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
57069 lv.scrollTop = bs.scrollTop = sb.scrollTop;
57072 handleScroll : function(e){
57074 var sb = this.scroller.dom;
57075 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
57079 handleWheel : function(e){
57080 var d = e.getWheelDelta();
57081 this.scroller.dom.scrollTop -= d*22;
57082 // set this here to prevent jumpy scrolling on large tables
57083 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
57087 renderRows : function(startRow, endRow){
57088 // pull in all the crap needed to render rows
57089 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
57090 var colCount = cm.getColumnCount();
57092 if(ds.getCount() < 1){
57096 // build a map for all the columns
57098 for(var i = 0; i < colCount; i++){
57099 var name = cm.getDataIndex(i);
57101 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57102 renderer : cm.getRenderer(i),
57103 id : cm.getColumnId(i),
57104 locked : cm.isLocked(i),
57105 has_editor : cm.isCellEditable(i)
57109 startRow = startRow || 0;
57110 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57112 // records to render
57113 var rs = ds.getRange(startRow, endRow);
57115 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57118 // As much as I hate to duplicate code, this was branched because FireFox really hates
57119 // [].join("") on strings. The performance difference was substantial enough to
57120 // branch this function
57121 doRender : Roo.isGecko ?
57122 function(cs, rs, ds, startRow, colCount, stripe){
57123 var ts = this.templates, ct = ts.cell, rt = ts.row;
57125 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57127 var hasListener = this.grid.hasListener('rowclass');
57129 for(var j = 0, len = rs.length; j < len; j++){
57130 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57131 for(var i = 0; i < colCount; i++){
57133 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57135 p.css = p.attr = "";
57136 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57137 if(p.value == undefined || p.value === "") {
57138 p.value = " ";
57141 p.css += ' x-grid-editable-cell';
57143 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57144 p.css += ' x-grid-dirty-cell';
57146 var markup = ct.apply(p);
57154 if(stripe && ((rowIndex+1) % 2 == 0)){
57155 alt.push("x-grid-row-alt")
57158 alt.push( " x-grid-dirty-row");
57161 if(this.getRowClass){
57162 alt.push(this.getRowClass(r, rowIndex));
57168 rowIndex : rowIndex,
57171 this.grid.fireEvent('rowclass', this, rowcfg);
57172 alt.push(rowcfg.rowClass);
57174 rp.alt = alt.join(" ");
57175 lbuf+= rt.apply(rp);
57177 buf+= rt.apply(rp);
57179 return [lbuf, buf];
57181 function(cs, rs, ds, startRow, colCount, stripe){
57182 var ts = this.templates, ct = ts.cell, rt = ts.row;
57184 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57185 var hasListener = this.grid.hasListener('rowclass');
57188 for(var j = 0, len = rs.length; j < len; j++){
57189 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57190 for(var i = 0; i < colCount; i++){
57192 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57194 p.css = p.attr = "";
57195 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57196 if(p.value == undefined || p.value === "") {
57197 p.value = " ";
57201 p.css += ' x-grid-editable-cell';
57203 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57204 p.css += ' x-grid-dirty-cell'
57207 var markup = ct.apply(p);
57209 cb[cb.length] = markup;
57211 lcb[lcb.length] = markup;
57215 if(stripe && ((rowIndex+1) % 2 == 0)){
57216 alt.push( "x-grid-row-alt");
57219 alt.push(" x-grid-dirty-row");
57222 if(this.getRowClass){
57223 alt.push( this.getRowClass(r, rowIndex));
57229 rowIndex : rowIndex,
57232 this.grid.fireEvent('rowclass', this, rowcfg);
57233 alt.push(rowcfg.rowClass);
57236 rp.alt = alt.join(" ");
57237 rp.cells = lcb.join("");
57238 lbuf[lbuf.length] = rt.apply(rp);
57239 rp.cells = cb.join("");
57240 buf[buf.length] = rt.apply(rp);
57242 return [lbuf.join(""), buf.join("")];
57245 renderBody : function(){
57246 var markup = this.renderRows();
57247 var bt = this.templates.body;
57248 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57252 * Refreshes the grid
57253 * @param {Boolean} headersToo
57255 refresh : function(headersToo){
57256 this.fireEvent("beforerefresh", this);
57257 this.grid.stopEditing();
57258 var result = this.renderBody();
57259 this.lockedBody.update(result[0]);
57260 this.mainBody.update(result[1]);
57261 if(headersToo === true){
57262 this.updateHeaders();
57263 this.updateColumns();
57264 this.updateSplitters();
57265 this.updateHeaderSortState();
57267 this.syncRowHeights();
57269 this.fireEvent("refresh", this);
57272 handleColumnMove : function(cm, oldIndex, newIndex){
57273 this.indexMap = null;
57274 var s = this.getScrollState();
57275 this.refresh(true);
57276 this.restoreScroll(s);
57277 this.afterMove(newIndex);
57280 afterMove : function(colIndex){
57281 if(this.enableMoveAnim && Roo.enableFx){
57282 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57284 // if multisort - fix sortOrder, and reload..
57285 if (this.grid.dataSource.multiSort) {
57286 // the we can call sort again..
57287 var dm = this.grid.dataSource;
57288 var cm = this.grid.colModel;
57290 for(var i = 0; i < cm.config.length; i++ ) {
57292 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57293 continue; // dont' bother, it's not in sort list or being set.
57296 so.push(cm.config[i].dataIndex);
57299 dm.load(dm.lastOptions);
57306 updateCell : function(dm, rowIndex, dataIndex){
57307 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57308 if(typeof colIndex == "undefined"){ // not present in grid
57311 var cm = this.grid.colModel;
57312 var cell = this.getCell(rowIndex, colIndex);
57313 var cellText = this.getCellText(rowIndex, colIndex);
57316 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57317 id : cm.getColumnId(colIndex),
57318 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57320 var renderer = cm.getRenderer(colIndex);
57321 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57322 if(typeof val == "undefined" || val === "") {
57325 cellText.innerHTML = val;
57326 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57327 this.syncRowHeights(rowIndex, rowIndex);
57330 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57332 if(this.grid.autoSizeHeaders){
57333 var h = this.getHeaderCellMeasure(colIndex);
57334 maxWidth = Math.max(maxWidth, h.scrollWidth);
57337 if(this.cm.isLocked(colIndex)){
57338 tb = this.getLockedTable();
57341 tb = this.getBodyTable();
57342 index = colIndex - this.cm.getLockedCount();
57345 var rows = tb.rows;
57346 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57347 for(var i = 0; i < stopIndex; i++){
57348 var cell = rows[i].childNodes[index].firstChild;
57349 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57352 return maxWidth + /*margin for error in IE*/ 5;
57355 * Autofit a column to its content.
57356 * @param {Number} colIndex
57357 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57359 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57360 if(this.cm.isHidden(colIndex)){
57361 return; // can't calc a hidden column
57364 var cid = this.cm.getColumnId(colIndex);
57365 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57366 if(this.grid.autoSizeHeaders){
57367 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57370 var newWidth = this.calcColumnWidth(colIndex);
57371 this.cm.setColumnWidth(colIndex,
57372 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57373 if(!suppressEvent){
57374 this.grid.fireEvent("columnresize", colIndex, newWidth);
57379 * Autofits all columns to their content and then expands to fit any extra space in the grid
57381 autoSizeColumns : function(){
57382 var cm = this.grid.colModel;
57383 var colCount = cm.getColumnCount();
57384 for(var i = 0; i < colCount; i++){
57385 this.autoSizeColumn(i, true, true);
57387 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57390 this.updateColumns();
57396 * Autofits all columns to the grid's width proportionate with their current size
57397 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57399 fitColumns : function(reserveScrollSpace){
57400 var cm = this.grid.colModel;
57401 var colCount = cm.getColumnCount();
57405 for (i = 0; i < colCount; i++){
57406 if(!cm.isHidden(i) && !cm.isFixed(i)){
57407 w = cm.getColumnWidth(i);
57413 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57414 if(reserveScrollSpace){
57417 var frac = (avail - cm.getTotalWidth())/width;
57418 while (cols.length){
57421 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57423 this.updateColumns();
57427 onRowSelect : function(rowIndex){
57428 var row = this.getRowComposite(rowIndex);
57429 row.addClass("x-grid-row-selected");
57432 onRowDeselect : function(rowIndex){
57433 var row = this.getRowComposite(rowIndex);
57434 row.removeClass("x-grid-row-selected");
57437 onCellSelect : function(row, col){
57438 var cell = this.getCell(row, col);
57440 Roo.fly(cell).addClass("x-grid-cell-selected");
57444 onCellDeselect : function(row, col){
57445 var cell = this.getCell(row, col);
57447 Roo.fly(cell).removeClass("x-grid-cell-selected");
57451 updateHeaderSortState : function(){
57453 // sort state can be single { field: xxx, direction : yyy}
57454 // or { xxx=>ASC , yyy : DESC ..... }
57457 if (!this.ds.multiSort) {
57458 var state = this.ds.getSortState();
57462 mstate[state.field] = state.direction;
57463 // FIXME... - this is not used here.. but might be elsewhere..
57464 this.sortState = state;
57467 mstate = this.ds.sortToggle;
57469 //remove existing sort classes..
57471 var sc = this.sortClasses;
57472 var hds = this.el.select(this.headerSelector).removeClass(sc);
57474 for(var f in mstate) {
57476 var sortColumn = this.cm.findColumnIndex(f);
57478 if(sortColumn != -1){
57479 var sortDir = mstate[f];
57480 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57489 handleHeaderClick : function(g, index,e){
57491 Roo.log("header click");
57494 // touch events on header are handled by context
57495 this.handleHdCtx(g,index,e);
57500 if(this.headersDisabled){
57503 var dm = g.dataSource, cm = g.colModel;
57504 if(!cm.isSortable(index)){
57509 if (dm.multiSort) {
57510 // update the sortOrder
57512 for(var i = 0; i < cm.config.length; i++ ) {
57514 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57515 continue; // dont' bother, it's not in sort list or being set.
57518 so.push(cm.config[i].dataIndex);
57524 dm.sort(cm.getDataIndex(index));
57528 destroy : function(){
57530 this.colMenu.removeAll();
57531 Roo.menu.MenuMgr.unregister(this.colMenu);
57532 this.colMenu.getEl().remove();
57533 delete this.colMenu;
57536 this.hmenu.removeAll();
57537 Roo.menu.MenuMgr.unregister(this.hmenu);
57538 this.hmenu.getEl().remove();
57541 if(this.grid.enableColumnMove){
57542 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57544 for(var dd in dds){
57545 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57546 var elid = dds[dd].dragElId;
57548 Roo.get(elid).remove();
57549 } else if(dds[dd].config.isTarget){
57550 dds[dd].proxyTop.remove();
57551 dds[dd].proxyBottom.remove();
57554 if(Roo.dd.DDM.locationCache[dd]){
57555 delete Roo.dd.DDM.locationCache[dd];
57558 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57561 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57562 this.bind(null, null);
57563 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57566 handleLockChange : function(){
57567 this.refresh(true);
57570 onDenyColumnLock : function(){
57574 onDenyColumnHide : function(){
57578 handleHdMenuClick : function(item){
57579 var index = this.hdCtxIndex;
57580 var cm = this.cm, ds = this.ds;
57583 ds.sort(cm.getDataIndex(index), "ASC");
57586 ds.sort(cm.getDataIndex(index), "DESC");
57589 var lc = cm.getLockedCount();
57590 if(cm.getColumnCount(true) <= lc+1){
57591 this.onDenyColumnLock();
57595 cm.setLocked(index, true, true);
57596 cm.moveColumn(index, lc);
57597 this.grid.fireEvent("columnmove", index, lc);
57599 cm.setLocked(index, true);
57603 var lc = cm.getLockedCount();
57604 if((lc-1) != index){
57605 cm.setLocked(index, false, true);
57606 cm.moveColumn(index, lc-1);
57607 this.grid.fireEvent("columnmove", index, lc-1);
57609 cm.setLocked(index, false);
57612 case 'wider': // used to expand cols on touch..
57614 var cw = cm.getColumnWidth(index);
57615 cw += (item.id == 'wider' ? 1 : -1) * 50;
57616 cw = Math.max(0, cw);
57617 cw = Math.min(cw,4000);
57618 cm.setColumnWidth(index, cw);
57622 index = cm.getIndexById(item.id.substr(4));
57624 if(item.checked && cm.getColumnCount(true) <= 1){
57625 this.onDenyColumnHide();
57628 cm.setHidden(index, item.checked);
57634 beforeColMenuShow : function(){
57635 var cm = this.cm, colCount = cm.getColumnCount();
57636 this.colMenu.removeAll();
57637 for(var i = 0; i < colCount; i++){
57638 this.colMenu.add(new Roo.menu.CheckItem({
57639 id: "col-"+cm.getColumnId(i),
57640 text: cm.getColumnHeader(i),
57641 checked: !cm.isHidden(i),
57647 handleHdCtx : function(g, index, e){
57649 var hd = this.getHeaderCell(index);
57650 this.hdCtxIndex = index;
57651 var ms = this.hmenu.items, cm = this.cm;
57652 ms.get("asc").setDisabled(!cm.isSortable(index));
57653 ms.get("desc").setDisabled(!cm.isSortable(index));
57654 if(this.grid.enableColLock !== false){
57655 ms.get("lock").setDisabled(cm.isLocked(index));
57656 ms.get("unlock").setDisabled(!cm.isLocked(index));
57658 this.hmenu.show(hd, "tl-bl");
57661 handleHdOver : function(e){
57662 var hd = this.findHeaderCell(e.getTarget());
57663 if(hd && !this.headersDisabled){
57664 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57665 this.fly(hd).addClass("x-grid-hd-over");
57670 handleHdOut : function(e){
57671 var hd = this.findHeaderCell(e.getTarget());
57673 this.fly(hd).removeClass("x-grid-hd-over");
57677 handleSplitDblClick : function(e, t){
57678 var i = this.getCellIndex(t);
57679 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57680 this.autoSizeColumn(i, true);
57685 render : function(){
57688 var colCount = cm.getColumnCount();
57690 if(this.grid.monitorWindowResize === true){
57691 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57693 var header = this.renderHeaders();
57694 var body = this.templates.body.apply({rows:""});
57695 var html = this.templates.master.apply({
57698 lockedHeader: header[0],
57702 //this.updateColumns();
57704 this.grid.getGridEl().dom.innerHTML = html;
57706 this.initElements();
57708 // a kludge to fix the random scolling effect in webkit
57709 this.el.on("scroll", function() {
57710 this.el.dom.scrollTop=0; // hopefully not recursive..
57713 this.scroller.on("scroll", this.handleScroll, this);
57714 this.lockedBody.on("mousewheel", this.handleWheel, this);
57715 this.mainBody.on("mousewheel", this.handleWheel, this);
57717 this.mainHd.on("mouseover", this.handleHdOver, this);
57718 this.mainHd.on("mouseout", this.handleHdOut, this);
57719 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57720 {delegate: "."+this.splitClass});
57722 this.lockedHd.on("mouseover", this.handleHdOver, this);
57723 this.lockedHd.on("mouseout", this.handleHdOut, this);
57724 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57725 {delegate: "."+this.splitClass});
57727 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57728 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57731 this.updateSplitters();
57733 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57734 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57735 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57738 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57739 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57741 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57742 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57744 if(this.grid.enableColLock !== false){
57745 this.hmenu.add('-',
57746 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57747 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57751 this.hmenu.add('-',
57752 {id:"wider", text: this.columnsWiderText},
57753 {id:"narrow", text: this.columnsNarrowText }
57759 if(this.grid.enableColumnHide !== false){
57761 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57762 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57763 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57765 this.hmenu.add('-',
57766 {id:"columns", text: this.columnsText, menu: this.colMenu}
57769 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57771 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57774 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57775 this.dd = new Roo.grid.GridDragZone(this.grid, {
57776 ddGroup : this.grid.ddGroup || 'GridDD'
57782 for(var i = 0; i < colCount; i++){
57783 if(cm.isHidden(i)){
57784 this.hideColumn(i);
57786 if(cm.config[i].align){
57787 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57788 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57792 this.updateHeaderSortState();
57794 this.beforeInitialResize();
57797 // two part rendering gives faster view to the user
57798 this.renderPhase2.defer(1, this);
57801 renderPhase2 : function(){
57802 // render the rows now
57804 if(this.grid.autoSizeColumns){
57805 this.autoSizeColumns();
57809 beforeInitialResize : function(){
57813 onColumnSplitterMoved : function(i, w){
57814 this.userResized = true;
57815 var cm = this.grid.colModel;
57816 cm.setColumnWidth(i, w, true);
57817 var cid = cm.getColumnId(i);
57818 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57819 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57820 this.updateSplitters();
57822 this.grid.fireEvent("columnresize", i, w);
57825 syncRowHeights : function(startIndex, endIndex){
57826 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
57827 startIndex = startIndex || 0;
57828 var mrows = this.getBodyTable().rows;
57829 var lrows = this.getLockedTable().rows;
57830 var len = mrows.length-1;
57831 endIndex = Math.min(endIndex || len, len);
57832 for(var i = startIndex; i <= endIndex; i++){
57833 var m = mrows[i], l = lrows[i];
57834 var h = Math.max(m.offsetHeight, l.offsetHeight);
57835 m.style.height = l.style.height = h + "px";
57840 layout : function(initialRender, is2ndPass)
57843 var auto = g.autoHeight;
57844 var scrollOffset = 16;
57845 var c = g.getGridEl(), cm = this.cm,
57846 expandCol = g.autoExpandColumn,
57848 //c.beginMeasure();
57850 if(!c.dom.offsetWidth){ // display:none?
57852 this.lockedWrap.show();
57853 this.mainWrap.show();
57858 var hasLock = this.cm.isLocked(0);
57860 var tbh = this.headerPanel.getHeight();
57861 var bbh = this.footerPanel.getHeight();
57864 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
57865 var newHeight = ch + c.getBorderWidth("tb");
57867 newHeight = Math.min(g.maxHeight, newHeight);
57869 c.setHeight(newHeight);
57873 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
57876 var s = this.scroller;
57878 var csize = c.getSize(true);
57880 this.el.setSize(csize.width, csize.height);
57882 this.headerPanel.setWidth(csize.width);
57883 this.footerPanel.setWidth(csize.width);
57885 var hdHeight = this.mainHd.getHeight();
57886 var vw = csize.width;
57887 var vh = csize.height - (tbh + bbh);
57891 var bt = this.getBodyTable();
57893 if(cm.getLockedCount() == cm.config.length){
57894 bt = this.getLockedTable();
57897 var ltWidth = hasLock ?
57898 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
57900 var scrollHeight = bt.offsetHeight;
57901 var scrollWidth = ltWidth + bt.offsetWidth;
57902 var vscroll = false, hscroll = false;
57904 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
57906 var lw = this.lockedWrap, mw = this.mainWrap;
57907 var lb = this.lockedBody, mb = this.mainBody;
57909 setTimeout(function(){
57910 var t = s.dom.offsetTop;
57911 var w = s.dom.clientWidth,
57912 h = s.dom.clientHeight;
57915 lw.setSize(ltWidth, h);
57917 mw.setLeftTop(ltWidth, t);
57918 mw.setSize(w-ltWidth, h);
57920 lb.setHeight(h-hdHeight);
57921 mb.setHeight(h-hdHeight);
57923 if(is2ndPass !== true && !gv.userResized && expandCol){
57924 // high speed resize without full column calculation
57926 var ci = cm.getIndexById(expandCol);
57928 ci = cm.findColumnIndex(expandCol);
57930 ci = Math.max(0, ci); // make sure it's got at least the first col.
57931 var expandId = cm.getColumnId(ci);
57932 var tw = cm.getTotalWidth(false);
57933 var currentWidth = cm.getColumnWidth(ci);
57934 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
57935 if(currentWidth != cw){
57936 cm.setColumnWidth(ci, cw, true);
57937 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57938 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57939 gv.updateSplitters();
57940 gv.layout(false, true);
57952 onWindowResize : function(){
57953 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
57959 appendFooter : function(parentEl){
57963 sortAscText : "Sort Ascending",
57964 sortDescText : "Sort Descending",
57965 lockText : "Lock Column",
57966 unlockText : "Unlock Column",
57967 columnsText : "Columns",
57969 columnsWiderText : "Wider",
57970 columnsNarrowText : "Thinner"
57974 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
57975 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
57976 this.proxy.el.addClass('x-grid3-col-dd');
57979 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
57980 handleMouseDown : function(e){
57984 callHandleMouseDown : function(e){
57985 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
57990 * Ext JS Library 1.1.1
57991 * Copyright(c) 2006-2007, Ext JS, LLC.
57993 * Originally Released Under LGPL - original licence link has changed is not relivant.
57996 * <script type="text/javascript">
58000 // This is a support class used internally by the Grid components
58001 Roo.grid.SplitDragZone = function(grid, hd, hd2){
58003 this.view = grid.getView();
58004 this.proxy = this.view.resizeProxy;
58005 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
58006 "gridSplitters" + this.grid.getGridEl().id, {
58007 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
58009 this.setHandleElId(Roo.id(hd));
58010 this.setOuterHandleElId(Roo.id(hd2));
58011 this.scroll = false;
58013 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
58014 fly: Roo.Element.fly,
58016 b4StartDrag : function(x, y){
58017 this.view.headersDisabled = true;
58018 this.proxy.setHeight(this.view.mainWrap.getHeight());
58019 var w = this.cm.getColumnWidth(this.cellIndex);
58020 var minw = Math.max(w-this.grid.minColumnWidth, 0);
58021 this.resetConstraints();
58022 this.setXConstraint(minw, 1000);
58023 this.setYConstraint(0, 0);
58024 this.minX = x - minw;
58025 this.maxX = x + 1000;
58027 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
58031 handleMouseDown : function(e){
58032 ev = Roo.EventObject.setEvent(e);
58033 var t = this.fly(ev.getTarget());
58034 if(t.hasClass("x-grid-split")){
58035 this.cellIndex = this.view.getCellIndex(t.dom);
58036 this.split = t.dom;
58037 this.cm = this.grid.colModel;
58038 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
58039 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
58044 endDrag : function(e){
58045 this.view.headersDisabled = false;
58046 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
58047 var diff = endX - this.startPos;
58048 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
58051 autoOffset : function(){
58052 this.setDelta(0,0);
58056 * Ext JS Library 1.1.1
58057 * Copyright(c) 2006-2007, Ext JS, LLC.
58059 * Originally Released Under LGPL - original licence link has changed is not relivant.
58062 * <script type="text/javascript">
58066 // This is a support class used internally by the Grid components
58067 Roo.grid.GridDragZone = function(grid, config){
58068 this.view = grid.getView();
58069 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
58070 if(this.view.lockedBody){
58071 this.setHandleElId(Roo.id(this.view.mainBody.dom));
58072 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
58074 this.scroll = false;
58076 this.ddel = document.createElement('div');
58077 this.ddel.className = 'x-grid-dd-wrap';
58080 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
58081 ddGroup : "GridDD",
58083 getDragData : function(e){
58084 var t = Roo.lib.Event.getTarget(e);
58085 var rowIndex = this.view.findRowIndex(t);
58086 var sm = this.grid.selModel;
58088 //Roo.log(rowIndex);
58090 if (sm.getSelectedCell) {
58091 // cell selection..
58092 if (!sm.getSelectedCell()) {
58095 if (rowIndex != sm.getSelectedCell()[0]) {
58100 if (sm.getSelections && sm.getSelections().length < 1) {
58105 // before it used to all dragging of unseleted... - now we dont do that.
58106 if(rowIndex !== false){
58111 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58113 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58116 if (e.hasModifier()){
58117 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58120 Roo.log("getDragData");
58125 rowIndex: rowIndex,
58126 selections: sm.getSelections ? sm.getSelections() : (
58127 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
58134 onInitDrag : function(e){
58135 var data = this.dragData;
58136 this.ddel.innerHTML = this.grid.getDragDropText();
58137 this.proxy.update(this.ddel);
58138 // fire start drag?
58141 afterRepair : function(){
58142 this.dragging = false;
58145 getRepairXY : function(e, data){
58149 onEndDrag : function(data, e){
58153 onValidDrop : function(dd, e, id){
58158 beforeInvalidDrop : function(e, id){
58163 * Ext JS Library 1.1.1
58164 * Copyright(c) 2006-2007, Ext JS, LLC.
58166 * Originally Released Under LGPL - original licence link has changed is not relivant.
58169 * <script type="text/javascript">
58174 * @class Roo.grid.ColumnModel
58175 * @extends Roo.util.Observable
58176 * This is the default implementation of a ColumnModel used by the Grid. It defines
58177 * the columns in the grid.
58180 var colModel = new Roo.grid.ColumnModel([
58181 {header: "Ticker", width: 60, sortable: true, locked: true},
58182 {header: "Company Name", width: 150, sortable: true},
58183 {header: "Market Cap.", width: 100, sortable: true},
58184 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58185 {header: "Employees", width: 100, sortable: true, resizable: false}
58190 * The config options listed for this class are options which may appear in each
58191 * individual column definition.
58192 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58194 * @param {Object} config An Array of column config objects. See this class's
58195 * config objects for details.
58197 Roo.grid.ColumnModel = function(config){
58199 * The config passed into the constructor
58201 this.config = config;
58204 // if no id, create one
58205 // if the column does not have a dataIndex mapping,
58206 // map it to the order it is in the config
58207 for(var i = 0, len = config.length; i < len; i++){
58209 if(typeof c.dataIndex == "undefined"){
58212 if(typeof c.renderer == "string"){
58213 c.renderer = Roo.util.Format[c.renderer];
58215 if(typeof c.id == "undefined"){
58218 if(c.editor && c.editor.xtype){
58219 c.editor = Roo.factory(c.editor, Roo.grid);
58221 if(c.editor && c.editor.isFormField){
58222 c.editor = new Roo.grid.GridEditor(c.editor);
58224 this.lookup[c.id] = c;
58228 * The width of columns which have no width specified (defaults to 100)
58231 this.defaultWidth = 100;
58234 * Default sortable of columns which have no sortable specified (defaults to false)
58237 this.defaultSortable = false;
58241 * @event widthchange
58242 * Fires when the width of a column changes.
58243 * @param {ColumnModel} this
58244 * @param {Number} columnIndex The column index
58245 * @param {Number} newWidth The new width
58247 "widthchange": true,
58249 * @event headerchange
58250 * Fires when the text of a header changes.
58251 * @param {ColumnModel} this
58252 * @param {Number} columnIndex The column index
58253 * @param {Number} newText The new header text
58255 "headerchange": true,
58257 * @event hiddenchange
58258 * Fires when a column is hidden or "unhidden".
58259 * @param {ColumnModel} this
58260 * @param {Number} columnIndex The column index
58261 * @param {Boolean} hidden true if hidden, false otherwise
58263 "hiddenchange": true,
58265 * @event columnmoved
58266 * Fires when a column is moved.
58267 * @param {ColumnModel} this
58268 * @param {Number} oldIndex
58269 * @param {Number} newIndex
58271 "columnmoved" : true,
58273 * @event columlockchange
58274 * Fires when a column's locked state is changed
58275 * @param {ColumnModel} this
58276 * @param {Number} colIndex
58277 * @param {Boolean} locked true if locked
58279 "columnlockchange" : true
58281 Roo.grid.ColumnModel.superclass.constructor.call(this);
58283 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58285 * @cfg {String} header The header text to display in the Grid view.
58288 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58289 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58290 * specified, the column's index is used as an index into the Record's data Array.
58293 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58294 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58297 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58298 * Defaults to the value of the {@link #defaultSortable} property.
58299 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58302 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58305 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58308 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58311 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58314 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58315 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58316 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58317 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58320 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58323 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58326 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58329 * @cfg {String} cursor (Optional)
58332 * @cfg {String} tooltip (Optional)
58335 * @cfg {Number} xs (Optional)
58338 * @cfg {Number} sm (Optional)
58341 * @cfg {Number} md (Optional)
58344 * @cfg {Number} lg (Optional)
58347 * Returns the id of the column at the specified index.
58348 * @param {Number} index The column index
58349 * @return {String} the id
58351 getColumnId : function(index){
58352 return this.config[index].id;
58356 * Returns the column for a specified id.
58357 * @param {String} id The column id
58358 * @return {Object} the column
58360 getColumnById : function(id){
58361 return this.lookup[id];
58366 * Returns the column for a specified dataIndex.
58367 * @param {String} dataIndex The column dataIndex
58368 * @return {Object|Boolean} the column or false if not found
58370 getColumnByDataIndex: function(dataIndex){
58371 var index = this.findColumnIndex(dataIndex);
58372 return index > -1 ? this.config[index] : false;
58376 * Returns the index for a specified column id.
58377 * @param {String} id The column id
58378 * @return {Number} the index, or -1 if not found
58380 getIndexById : function(id){
58381 for(var i = 0, len = this.config.length; i < len; i++){
58382 if(this.config[i].id == id){
58390 * Returns the index for a specified column dataIndex.
58391 * @param {String} dataIndex The column dataIndex
58392 * @return {Number} the index, or -1 if not found
58395 findColumnIndex : function(dataIndex){
58396 for(var i = 0, len = this.config.length; i < len; i++){
58397 if(this.config[i].dataIndex == dataIndex){
58405 moveColumn : function(oldIndex, newIndex){
58406 var c = this.config[oldIndex];
58407 this.config.splice(oldIndex, 1);
58408 this.config.splice(newIndex, 0, c);
58409 this.dataMap = null;
58410 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58413 isLocked : function(colIndex){
58414 return this.config[colIndex].locked === true;
58417 setLocked : function(colIndex, value, suppressEvent){
58418 if(this.isLocked(colIndex) == value){
58421 this.config[colIndex].locked = value;
58422 if(!suppressEvent){
58423 this.fireEvent("columnlockchange", this, colIndex, value);
58427 getTotalLockedWidth : function(){
58428 var totalWidth = 0;
58429 for(var i = 0; i < this.config.length; i++){
58430 if(this.isLocked(i) && !this.isHidden(i)){
58431 this.totalWidth += this.getColumnWidth(i);
58437 getLockedCount : function(){
58438 for(var i = 0, len = this.config.length; i < len; i++){
58439 if(!this.isLocked(i)){
58444 return this.config.length;
58448 * Returns the number of columns.
58451 getColumnCount : function(visibleOnly){
58452 if(visibleOnly === true){
58454 for(var i = 0, len = this.config.length; i < len; i++){
58455 if(!this.isHidden(i)){
58461 return this.config.length;
58465 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58466 * @param {Function} fn
58467 * @param {Object} scope (optional)
58468 * @return {Array} result
58470 getColumnsBy : function(fn, scope){
58472 for(var i = 0, len = this.config.length; i < len; i++){
58473 var c = this.config[i];
58474 if(fn.call(scope||this, c, i) === true){
58482 * Returns true if the specified column is sortable.
58483 * @param {Number} col The column index
58484 * @return {Boolean}
58486 isSortable : function(col){
58487 if(typeof this.config[col].sortable == "undefined"){
58488 return this.defaultSortable;
58490 return this.config[col].sortable;
58494 * Returns the rendering (formatting) function defined for the column.
58495 * @param {Number} col The column index.
58496 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58498 getRenderer : function(col){
58499 if(!this.config[col].renderer){
58500 return Roo.grid.ColumnModel.defaultRenderer;
58502 return this.config[col].renderer;
58506 * Sets the rendering (formatting) function for a column.
58507 * @param {Number} col The column index
58508 * @param {Function} fn The function to use to process the cell's raw data
58509 * to return HTML markup for the grid view. The render function is called with
58510 * the following parameters:<ul>
58511 * <li>Data value.</li>
58512 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58513 * <li>css A CSS style string to apply to the table cell.</li>
58514 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58515 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58516 * <li>Row index</li>
58517 * <li>Column index</li>
58518 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58520 setRenderer : function(col, fn){
58521 this.config[col].renderer = fn;
58525 * Returns the width for the specified column.
58526 * @param {Number} col The column index
58529 getColumnWidth : function(col){
58530 return this.config[col].width * 1 || this.defaultWidth;
58534 * Sets the width for a column.
58535 * @param {Number} col The column index
58536 * @param {Number} width The new width
58538 setColumnWidth : function(col, width, suppressEvent){
58539 this.config[col].width = width;
58540 this.totalWidth = null;
58541 if(!suppressEvent){
58542 this.fireEvent("widthchange", this, col, width);
58547 * Returns the total width of all columns.
58548 * @param {Boolean} includeHidden True to include hidden column widths
58551 getTotalWidth : function(includeHidden){
58552 if(!this.totalWidth){
58553 this.totalWidth = 0;
58554 for(var i = 0, len = this.config.length; i < len; i++){
58555 if(includeHidden || !this.isHidden(i)){
58556 this.totalWidth += this.getColumnWidth(i);
58560 return this.totalWidth;
58564 * Returns the header for the specified column.
58565 * @param {Number} col The column index
58568 getColumnHeader : function(col){
58569 return this.config[col].header;
58573 * Sets the header for a column.
58574 * @param {Number} col The column index
58575 * @param {String} header The new header
58577 setColumnHeader : function(col, header){
58578 this.config[col].header = header;
58579 this.fireEvent("headerchange", this, col, header);
58583 * Returns the tooltip for the specified column.
58584 * @param {Number} col The column index
58587 getColumnTooltip : function(col){
58588 return this.config[col].tooltip;
58591 * Sets the tooltip for a column.
58592 * @param {Number} col The column index
58593 * @param {String} tooltip The new tooltip
58595 setColumnTooltip : function(col, tooltip){
58596 this.config[col].tooltip = tooltip;
58600 * Returns the dataIndex for the specified column.
58601 * @param {Number} col The column index
58604 getDataIndex : function(col){
58605 return this.config[col].dataIndex;
58609 * Sets the dataIndex for a column.
58610 * @param {Number} col The column index
58611 * @param {Number} dataIndex The new dataIndex
58613 setDataIndex : function(col, dataIndex){
58614 this.config[col].dataIndex = dataIndex;
58620 * Returns true if the cell is editable.
58621 * @param {Number} colIndex The column index
58622 * @param {Number} rowIndex The row index - this is nto actually used..?
58623 * @return {Boolean}
58625 isCellEditable : function(colIndex, rowIndex){
58626 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58630 * Returns the editor defined for the cell/column.
58631 * return false or null to disable editing.
58632 * @param {Number} colIndex The column index
58633 * @param {Number} rowIndex The row index
58636 getCellEditor : function(colIndex, rowIndex){
58637 return this.config[colIndex].editor;
58641 * Sets if a column is editable.
58642 * @param {Number} col The column index
58643 * @param {Boolean} editable True if the column is editable
58645 setEditable : function(col, editable){
58646 this.config[col].editable = editable;
58651 * Returns true if the column is hidden.
58652 * @param {Number} colIndex The column index
58653 * @return {Boolean}
58655 isHidden : function(colIndex){
58656 return this.config[colIndex].hidden;
58661 * Returns true if the column width cannot be changed
58663 isFixed : function(colIndex){
58664 return this.config[colIndex].fixed;
58668 * Returns true if the column can be resized
58669 * @return {Boolean}
58671 isResizable : function(colIndex){
58672 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58675 * Sets if a column is hidden.
58676 * @param {Number} colIndex The column index
58677 * @param {Boolean} hidden True if the column is hidden
58679 setHidden : function(colIndex, hidden){
58680 this.config[colIndex].hidden = hidden;
58681 this.totalWidth = null;
58682 this.fireEvent("hiddenchange", this, colIndex, hidden);
58686 * Sets the editor for a column.
58687 * @param {Number} col The column index
58688 * @param {Object} editor The editor object
58690 setEditor : function(col, editor){
58691 this.config[col].editor = editor;
58695 Roo.grid.ColumnModel.defaultRenderer = function(value)
58697 if(typeof value == "object") {
58700 if(typeof value == "string" && value.length < 1){
58704 return String.format("{0}", value);
58707 // Alias for backwards compatibility
58708 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
58711 * Ext JS Library 1.1.1
58712 * Copyright(c) 2006-2007, Ext JS, LLC.
58714 * Originally Released Under LGPL - original licence link has changed is not relivant.
58717 * <script type="text/javascript">
58721 * @class Roo.grid.AbstractSelectionModel
58722 * @extends Roo.util.Observable
58723 * Abstract base class for grid SelectionModels. It provides the interface that should be
58724 * implemented by descendant classes. This class should not be directly instantiated.
58727 Roo.grid.AbstractSelectionModel = function(){
58728 this.locked = false;
58729 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
58732 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
58733 /** @ignore Called by the grid automatically. Do not call directly. */
58734 init : function(grid){
58740 * Locks the selections.
58743 this.locked = true;
58747 * Unlocks the selections.
58749 unlock : function(){
58750 this.locked = false;
58754 * Returns true if the selections are locked.
58755 * @return {Boolean}
58757 isLocked : function(){
58758 return this.locked;
58762 * Ext JS Library 1.1.1
58763 * Copyright(c) 2006-2007, Ext JS, LLC.
58765 * Originally Released Under LGPL - original licence link has changed is not relivant.
58768 * <script type="text/javascript">
58771 * @extends Roo.grid.AbstractSelectionModel
58772 * @class Roo.grid.RowSelectionModel
58773 * The default SelectionModel used by {@link Roo.grid.Grid}.
58774 * It supports multiple selections and keyboard selection/navigation.
58776 * @param {Object} config
58778 Roo.grid.RowSelectionModel = function(config){
58779 Roo.apply(this, config);
58780 this.selections = new Roo.util.MixedCollection(false, function(o){
58785 this.lastActive = false;
58789 * @event selectionchange
58790 * Fires when the selection changes
58791 * @param {SelectionModel} this
58793 "selectionchange" : true,
58795 * @event afterselectionchange
58796 * Fires after the selection changes (eg. by key press or clicking)
58797 * @param {SelectionModel} this
58799 "afterselectionchange" : true,
58801 * @event beforerowselect
58802 * Fires when a row is selected being selected, return false to cancel.
58803 * @param {SelectionModel} this
58804 * @param {Number} rowIndex The selected index
58805 * @param {Boolean} keepExisting False if other selections will be cleared
58807 "beforerowselect" : true,
58810 * Fires when a row is selected.
58811 * @param {SelectionModel} this
58812 * @param {Number} rowIndex The selected index
58813 * @param {Roo.data.Record} r The record
58815 "rowselect" : true,
58817 * @event rowdeselect
58818 * Fires when a row is deselected.
58819 * @param {SelectionModel} this
58820 * @param {Number} rowIndex The selected index
58822 "rowdeselect" : true
58824 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
58825 this.locked = false;
58828 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
58830 * @cfg {Boolean} singleSelect
58831 * True to allow selection of only one row at a time (defaults to false)
58833 singleSelect : false,
58836 initEvents : function(){
58838 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
58839 this.grid.on("mousedown", this.handleMouseDown, this);
58840 }else{ // allow click to work like normal
58841 this.grid.on("rowclick", this.handleDragableRowClick, this);
58844 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
58845 "up" : function(e){
58847 this.selectPrevious(e.shiftKey);
58848 }else if(this.last !== false && this.lastActive !== false){
58849 var last = this.last;
58850 this.selectRange(this.last, this.lastActive-1);
58851 this.grid.getView().focusRow(this.lastActive);
58852 if(last !== false){
58856 this.selectFirstRow();
58858 this.fireEvent("afterselectionchange", this);
58860 "down" : function(e){
58862 this.selectNext(e.shiftKey);
58863 }else if(this.last !== false && this.lastActive !== false){
58864 var last = this.last;
58865 this.selectRange(this.last, this.lastActive+1);
58866 this.grid.getView().focusRow(this.lastActive);
58867 if(last !== false){
58871 this.selectFirstRow();
58873 this.fireEvent("afterselectionchange", this);
58878 var view = this.grid.view;
58879 view.on("refresh", this.onRefresh, this);
58880 view.on("rowupdated", this.onRowUpdated, this);
58881 view.on("rowremoved", this.onRemove, this);
58885 onRefresh : function(){
58886 var ds = this.grid.dataSource, i, v = this.grid.view;
58887 var s = this.selections;
58888 s.each(function(r){
58889 if((i = ds.indexOfId(r.id)) != -1){
58891 s.add(ds.getAt(i)); // updating the selection relate data
58899 onRemove : function(v, index, r){
58900 this.selections.remove(r);
58904 onRowUpdated : function(v, index, r){
58905 if(this.isSelected(r)){
58906 v.onRowSelect(index);
58912 * @param {Array} records The records to select
58913 * @param {Boolean} keepExisting (optional) True to keep existing selections
58915 selectRecords : function(records, keepExisting){
58917 this.clearSelections();
58919 var ds = this.grid.dataSource;
58920 for(var i = 0, len = records.length; i < len; i++){
58921 this.selectRow(ds.indexOf(records[i]), true);
58926 * Gets the number of selected rows.
58929 getCount : function(){
58930 return this.selections.length;
58934 * Selects the first row in the grid.
58936 selectFirstRow : function(){
58941 * Select the last row.
58942 * @param {Boolean} keepExisting (optional) True to keep existing selections
58944 selectLastRow : function(keepExisting){
58945 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
58949 * Selects the row immediately following the last selected row.
58950 * @param {Boolean} keepExisting (optional) True to keep existing selections
58952 selectNext : function(keepExisting){
58953 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
58954 this.selectRow(this.last+1, keepExisting);
58955 this.grid.getView().focusRow(this.last);
58960 * Selects the row that precedes the last selected row.
58961 * @param {Boolean} keepExisting (optional) True to keep existing selections
58963 selectPrevious : function(keepExisting){
58965 this.selectRow(this.last-1, keepExisting);
58966 this.grid.getView().focusRow(this.last);
58971 * Returns the selected records
58972 * @return {Array} Array of selected records
58974 getSelections : function(){
58975 return [].concat(this.selections.items);
58979 * Returns the first selected record.
58982 getSelected : function(){
58983 return this.selections.itemAt(0);
58988 * Clears all selections.
58990 clearSelections : function(fast){
58995 var ds = this.grid.dataSource;
58996 var s = this.selections;
58997 s.each(function(r){
58998 this.deselectRow(ds.indexOfId(r.id));
59002 this.selections.clear();
59009 * Selects all rows.
59011 selectAll : function(){
59015 this.selections.clear();
59016 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
59017 this.selectRow(i, true);
59022 * Returns True if there is a selection.
59023 * @return {Boolean}
59025 hasSelection : function(){
59026 return this.selections.length > 0;
59030 * Returns True if the specified row is selected.
59031 * @param {Number/Record} record The record or index of the record to check
59032 * @return {Boolean}
59034 isSelected : function(index){
59035 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
59036 return (r && this.selections.key(r.id) ? true : false);
59040 * Returns True if the specified record id is selected.
59041 * @param {String} id The id of record to check
59042 * @return {Boolean}
59044 isIdSelected : function(id){
59045 return (this.selections.key(id) ? true : false);
59049 handleMouseDown : function(e, t){
59050 var view = this.grid.getView(), rowIndex;
59051 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
59054 if(e.shiftKey && this.last !== false){
59055 var last = this.last;
59056 this.selectRange(last, rowIndex, e.ctrlKey);
59057 this.last = last; // reset the last
59058 view.focusRow(rowIndex);
59060 var isSelected = this.isSelected(rowIndex);
59061 if(e.button !== 0 && isSelected){
59062 view.focusRow(rowIndex);
59063 }else if(e.ctrlKey && isSelected){
59064 this.deselectRow(rowIndex);
59065 }else if(!isSelected){
59066 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
59067 view.focusRow(rowIndex);
59070 this.fireEvent("afterselectionchange", this);
59073 handleDragableRowClick : function(grid, rowIndex, e)
59075 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
59076 this.selectRow(rowIndex, false);
59077 grid.view.focusRow(rowIndex);
59078 this.fireEvent("afterselectionchange", this);
59083 * Selects multiple rows.
59084 * @param {Array} rows Array of the indexes of the row to select
59085 * @param {Boolean} keepExisting (optional) True to keep existing selections
59087 selectRows : function(rows, keepExisting){
59089 this.clearSelections();
59091 for(var i = 0, len = rows.length; i < len; i++){
59092 this.selectRow(rows[i], true);
59097 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59098 * @param {Number} startRow The index of the first row in the range
59099 * @param {Number} endRow The index of the last row in the range
59100 * @param {Boolean} keepExisting (optional) True to retain existing selections
59102 selectRange : function(startRow, endRow, keepExisting){
59107 this.clearSelections();
59109 if(startRow <= endRow){
59110 for(var i = startRow; i <= endRow; i++){
59111 this.selectRow(i, true);
59114 for(var i = startRow; i >= endRow; i--){
59115 this.selectRow(i, true);
59121 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59122 * @param {Number} startRow The index of the first row in the range
59123 * @param {Number} endRow The index of the last row in the range
59125 deselectRange : function(startRow, endRow, preventViewNotify){
59129 for(var i = startRow; i <= endRow; i++){
59130 this.deselectRow(i, preventViewNotify);
59136 * @param {Number} row The index of the row to select
59137 * @param {Boolean} keepExisting (optional) True to keep existing selections
59139 selectRow : function(index, keepExisting, preventViewNotify){
59140 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
59143 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59144 if(!keepExisting || this.singleSelect){
59145 this.clearSelections();
59147 var r = this.grid.dataSource.getAt(index);
59148 this.selections.add(r);
59149 this.last = this.lastActive = index;
59150 if(!preventViewNotify){
59151 this.grid.getView().onRowSelect(index);
59153 this.fireEvent("rowselect", this, index, r);
59154 this.fireEvent("selectionchange", this);
59160 * @param {Number} row The index of the row to deselect
59162 deselectRow : function(index, preventViewNotify){
59166 if(this.last == index){
59169 if(this.lastActive == index){
59170 this.lastActive = false;
59172 var r = this.grid.dataSource.getAt(index);
59173 this.selections.remove(r);
59174 if(!preventViewNotify){
59175 this.grid.getView().onRowDeselect(index);
59177 this.fireEvent("rowdeselect", this, index);
59178 this.fireEvent("selectionchange", this);
59182 restoreLast : function(){
59184 this.last = this._last;
59189 acceptsNav : function(row, col, cm){
59190 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59194 onEditorKey : function(field, e){
59195 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59200 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59202 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59204 }else if(k == e.ENTER && !e.ctrlKey){
59208 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59210 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59212 }else if(k == e.ESC){
59216 g.startEditing(newCell[0], newCell[1]);
59221 * Ext JS Library 1.1.1
59222 * Copyright(c) 2006-2007, Ext JS, LLC.
59224 * Originally Released Under LGPL - original licence link has changed is not relivant.
59227 * <script type="text/javascript">
59230 * @class Roo.grid.CellSelectionModel
59231 * @extends Roo.grid.AbstractSelectionModel
59232 * This class provides the basic implementation for cell selection in a grid.
59234 * @param {Object} config The object containing the configuration of this model.
59235 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59237 Roo.grid.CellSelectionModel = function(config){
59238 Roo.apply(this, config);
59240 this.selection = null;
59244 * @event beforerowselect
59245 * Fires before a cell is selected.
59246 * @param {SelectionModel} this
59247 * @param {Number} rowIndex The selected row index
59248 * @param {Number} colIndex The selected cell index
59250 "beforecellselect" : true,
59252 * @event cellselect
59253 * Fires when a cell is selected.
59254 * @param {SelectionModel} this
59255 * @param {Number} rowIndex The selected row index
59256 * @param {Number} colIndex The selected cell index
59258 "cellselect" : true,
59260 * @event selectionchange
59261 * Fires when the active selection changes.
59262 * @param {SelectionModel} this
59263 * @param {Object} selection null for no selection or an object (o) with two properties
59265 <li>o.record: the record object for the row the selection is in</li>
59266 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59269 "selectionchange" : true,
59272 * Fires when the tab (or enter) was pressed on the last editable cell
59273 * You can use this to trigger add new row.
59274 * @param {SelectionModel} this
59278 * @event beforeeditnext
59279 * Fires before the next editable sell is made active
59280 * You can use this to skip to another cell or fire the tabend
59281 * if you set cell to false
59282 * @param {Object} eventdata object : { cell : [ row, col ] }
59284 "beforeeditnext" : true
59286 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59289 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59291 enter_is_tab: false,
59294 initEvents : function(){
59295 this.grid.on("mousedown", this.handleMouseDown, this);
59296 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59297 var view = this.grid.view;
59298 view.on("refresh", this.onViewChange, this);
59299 view.on("rowupdated", this.onRowUpdated, this);
59300 view.on("beforerowremoved", this.clearSelections, this);
59301 view.on("beforerowsinserted", this.clearSelections, this);
59302 if(this.grid.isEditor){
59303 this.grid.on("beforeedit", this.beforeEdit, this);
59308 beforeEdit : function(e){
59309 this.select(e.row, e.column, false, true, e.record);
59313 onRowUpdated : function(v, index, r){
59314 if(this.selection && this.selection.record == r){
59315 v.onCellSelect(index, this.selection.cell[1]);
59320 onViewChange : function(){
59321 this.clearSelections(true);
59325 * Returns the currently selected cell,.
59326 * @return {Array} The selected cell (row, column) or null if none selected.
59328 getSelectedCell : function(){
59329 return this.selection ? this.selection.cell : null;
59333 * Clears all selections.
59334 * @param {Boolean} true to prevent the gridview from being notified about the change.
59336 clearSelections : function(preventNotify){
59337 var s = this.selection;
59339 if(preventNotify !== true){
59340 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59342 this.selection = null;
59343 this.fireEvent("selectionchange", this, null);
59348 * Returns true if there is a selection.
59349 * @return {Boolean}
59351 hasSelection : function(){
59352 return this.selection ? true : false;
59356 handleMouseDown : function(e, t){
59357 var v = this.grid.getView();
59358 if(this.isLocked()){
59361 var row = v.findRowIndex(t);
59362 var cell = v.findCellIndex(t);
59363 if(row !== false && cell !== false){
59364 this.select(row, cell);
59370 * @param {Number} rowIndex
59371 * @param {Number} collIndex
59373 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59374 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59375 this.clearSelections();
59376 r = r || this.grid.dataSource.getAt(rowIndex);
59379 cell : [rowIndex, colIndex]
59381 if(!preventViewNotify){
59382 var v = this.grid.getView();
59383 v.onCellSelect(rowIndex, colIndex);
59384 if(preventFocus !== true){
59385 v.focusCell(rowIndex, colIndex);
59388 this.fireEvent("cellselect", this, rowIndex, colIndex);
59389 this.fireEvent("selectionchange", this, this.selection);
59394 isSelectable : function(rowIndex, colIndex, cm){
59395 return !cm.isHidden(colIndex);
59399 handleKeyDown : function(e){
59400 //Roo.log('Cell Sel Model handleKeyDown');
59401 if(!e.isNavKeyPress()){
59404 var g = this.grid, s = this.selection;
59407 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59409 this.select(cell[0], cell[1]);
59414 var walk = function(row, col, step){
59415 return g.walkCells(row, col, step, sm.isSelectable, sm);
59417 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59424 // handled by onEditorKey
59425 if (g.isEditor && g.editing) {
59429 newCell = walk(r, c-1, -1);
59431 newCell = walk(r, c+1, 1);
59436 newCell = walk(r+1, c, 1);
59440 newCell = walk(r-1, c, -1);
59444 newCell = walk(r, c+1, 1);
59448 newCell = walk(r, c-1, -1);
59453 if(g.isEditor && !g.editing){
59454 g.startEditing(r, c);
59463 this.select(newCell[0], newCell[1]);
59469 acceptsNav : function(row, col, cm){
59470 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59474 * @param {Number} field (not used) - as it's normally used as a listener
59475 * @param {Number} e - event - fake it by using
59477 * var e = Roo.EventObjectImpl.prototype;
59478 * e.keyCode = e.TAB
59482 onEditorKey : function(field, e){
59484 var k = e.getKey(),
59487 ed = g.activeEditor,
59489 ///Roo.log('onEditorKey' + k);
59492 if (this.enter_is_tab && k == e.ENTER) {
59498 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59500 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59506 } else if(k == e.ENTER && !e.ctrlKey){
59509 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59511 } else if(k == e.ESC){
59516 var ecall = { cell : newCell, forward : forward };
59517 this.fireEvent('beforeeditnext', ecall );
59518 newCell = ecall.cell;
59519 forward = ecall.forward;
59523 //Roo.log('next cell after edit');
59524 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59525 } else if (forward) {
59526 // tabbed past last
59527 this.fireEvent.defer(100, this, ['tabend',this]);
59532 * Ext JS Library 1.1.1
59533 * Copyright(c) 2006-2007, Ext JS, LLC.
59535 * Originally Released Under LGPL - original licence link has changed is not relivant.
59538 * <script type="text/javascript">
59542 * @class Roo.grid.EditorGrid
59543 * @extends Roo.grid.Grid
59544 * Class for creating and editable grid.
59545 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59546 * The container MUST have some type of size defined for the grid to fill. The container will be
59547 * automatically set to position relative if it isn't already.
59548 * @param {Object} dataSource The data model to bind to
59549 * @param {Object} colModel The column model with info about this grid's columns
59551 Roo.grid.EditorGrid = function(container, config){
59552 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59553 this.getGridEl().addClass("xedit-grid");
59555 if(!this.selModel){
59556 this.selModel = new Roo.grid.CellSelectionModel();
59559 this.activeEditor = null;
59563 * @event beforeedit
59564 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59565 * <ul style="padding:5px;padding-left:16px;">
59566 * <li>grid - This grid</li>
59567 * <li>record - The record being edited</li>
59568 * <li>field - The field name being edited</li>
59569 * <li>value - The value for the field being edited.</li>
59570 * <li>row - The grid row index</li>
59571 * <li>column - The grid column index</li>
59572 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59574 * @param {Object} e An edit event (see above for description)
59576 "beforeedit" : true,
59579 * Fires after a cell is edited. <br />
59580 * <ul style="padding:5px;padding-left:16px;">
59581 * <li>grid - This grid</li>
59582 * <li>record - The record being edited</li>
59583 * <li>field - The field name being edited</li>
59584 * <li>value - The value being set</li>
59585 * <li>originalValue - The original value for the field, before the edit.</li>
59586 * <li>row - The grid row index</li>
59587 * <li>column - The grid column index</li>
59589 * @param {Object} e An edit event (see above for description)
59591 "afteredit" : true,
59593 * @event validateedit
59594 * Fires after a cell is edited, but before the value is set in the record.
59595 * You can use this to modify the value being set in the field, Return false
59596 * to cancel the change. The edit event object has the following properties <br />
59597 * <ul style="padding:5px;padding-left:16px;">
59598 * <li>editor - This editor</li>
59599 * <li>grid - This grid</li>
59600 * <li>record - The record being edited</li>
59601 * <li>field - The field name being edited</li>
59602 * <li>value - The value being set</li>
59603 * <li>originalValue - The original value for the field, before the edit.</li>
59604 * <li>row - The grid row index</li>
59605 * <li>column - The grid column index</li>
59606 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59608 * @param {Object} e An edit event (see above for description)
59610 "validateedit" : true
59612 this.on("bodyscroll", this.stopEditing, this);
59613 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59616 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59618 * @cfg {Number} clicksToEdit
59619 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59626 trackMouseOver: false, // causes very odd FF errors
59628 onCellDblClick : function(g, row, col){
59629 this.startEditing(row, col);
59632 onEditComplete : function(ed, value, startValue){
59633 this.editing = false;
59634 this.activeEditor = null;
59635 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59637 var field = this.colModel.getDataIndex(ed.col);
59642 originalValue: startValue,
59649 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59652 if(String(value) !== String(startValue)){
59654 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59655 r.set(field, e.value);
59656 // if we are dealing with a combo box..
59657 // then we also set the 'name' colum to be the displayField
59658 if (ed.field.displayField && ed.field.name) {
59659 r.set(ed.field.name, ed.field.el.dom.value);
59662 delete e.cancel; //?? why!!!
59663 this.fireEvent("afteredit", e);
59666 this.fireEvent("afteredit", e); // always fire it!
59668 this.view.focusCell(ed.row, ed.col);
59672 * Starts editing the specified for the specified row/column
59673 * @param {Number} rowIndex
59674 * @param {Number} colIndex
59676 startEditing : function(row, col){
59677 this.stopEditing();
59678 if(this.colModel.isCellEditable(col, row)){
59679 this.view.ensureVisible(row, col, true);
59681 var r = this.dataSource.getAt(row);
59682 var field = this.colModel.getDataIndex(col);
59683 var cell = Roo.get(this.view.getCell(row,col));
59688 value: r.data[field],
59693 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59694 this.editing = true;
59695 var ed = this.colModel.getCellEditor(col, row);
59701 ed.render(ed.parentEl || document.body);
59707 (function(){ // complex but required for focus issues in safari, ie and opera
59711 ed.on("complete", this.onEditComplete, this, {single: true});
59712 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
59713 this.activeEditor = ed;
59714 var v = r.data[field];
59715 ed.startEdit(this.view.getCell(row, col), v);
59716 // combo's with 'displayField and name set
59717 if (ed.field.displayField && ed.field.name) {
59718 ed.field.el.dom.value = r.data[ed.field.name];
59722 }).defer(50, this);
59728 * Stops any active editing
59730 stopEditing : function(){
59731 if(this.activeEditor){
59732 this.activeEditor.completeEdit();
59734 this.activeEditor = null;
59738 * Called to get grid's drag proxy text, by default returns this.ddText.
59741 getDragDropText : function(){
59742 var count = this.selModel.getSelectedCell() ? 1 : 0;
59743 return String.format(this.ddText, count, count == 1 ? '' : 's');
59748 * Ext JS Library 1.1.1
59749 * Copyright(c) 2006-2007, Ext JS, LLC.
59751 * Originally Released Under LGPL - original licence link has changed is not relivant.
59754 * <script type="text/javascript">
59757 // private - not really -- you end up using it !
59758 // This is a support class used internally by the Grid components
59761 * @class Roo.grid.GridEditor
59762 * @extends Roo.Editor
59763 * Class for creating and editable grid elements.
59764 * @param {Object} config any settings (must include field)
59766 Roo.grid.GridEditor = function(field, config){
59767 if (!config && field.field) {
59769 field = Roo.factory(config.field, Roo.form);
59771 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
59772 field.monitorTab = false;
59775 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
59778 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
59781 alignment: "tl-tl",
59784 cls: "x-small-editor x-grid-editor",
59789 * Ext JS Library 1.1.1
59790 * Copyright(c) 2006-2007, Ext JS, LLC.
59792 * Originally Released Under LGPL - original licence link has changed is not relivant.
59795 * <script type="text/javascript">
59800 Roo.grid.PropertyRecord = Roo.data.Record.create([
59801 {name:'name',type:'string'}, 'value'
59805 Roo.grid.PropertyStore = function(grid, source){
59807 this.store = new Roo.data.Store({
59808 recordType : Roo.grid.PropertyRecord
59810 this.store.on('update', this.onUpdate, this);
59812 this.setSource(source);
59814 Roo.grid.PropertyStore.superclass.constructor.call(this);
59819 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
59820 setSource : function(o){
59822 this.store.removeAll();
59825 if(this.isEditableValue(o[k])){
59826 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
59829 this.store.loadRecords({records: data}, {}, true);
59832 onUpdate : function(ds, record, type){
59833 if(type == Roo.data.Record.EDIT){
59834 var v = record.data['value'];
59835 var oldValue = record.modified['value'];
59836 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
59837 this.source[record.id] = v;
59839 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
59846 getProperty : function(row){
59847 return this.store.getAt(row);
59850 isEditableValue: function(val){
59851 if(val && val instanceof Date){
59853 }else if(typeof val == 'object' || typeof val == 'function'){
59859 setValue : function(prop, value){
59860 this.source[prop] = value;
59861 this.store.getById(prop).set('value', value);
59864 getSource : function(){
59865 return this.source;
59869 Roo.grid.PropertyColumnModel = function(grid, store){
59872 g.PropertyColumnModel.superclass.constructor.call(this, [
59873 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
59874 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
59876 this.store = store;
59877 this.bselect = Roo.DomHelper.append(document.body, {
59878 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
59879 {tag: 'option', value: 'true', html: 'true'},
59880 {tag: 'option', value: 'false', html: 'false'}
59883 Roo.id(this.bselect);
59886 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
59887 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
59888 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
59889 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
59890 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
59892 this.renderCellDelegate = this.renderCell.createDelegate(this);
59893 this.renderPropDelegate = this.renderProp.createDelegate(this);
59896 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
59900 valueText : 'Value',
59902 dateFormat : 'm/j/Y',
59905 renderDate : function(dateVal){
59906 return dateVal.dateFormat(this.dateFormat);
59909 renderBool : function(bVal){
59910 return bVal ? 'true' : 'false';
59913 isCellEditable : function(colIndex, rowIndex){
59914 return colIndex == 1;
59917 getRenderer : function(col){
59919 this.renderCellDelegate : this.renderPropDelegate;
59922 renderProp : function(v){
59923 return this.getPropertyName(v);
59926 renderCell : function(val){
59928 if(val instanceof Date){
59929 rv = this.renderDate(val);
59930 }else if(typeof val == 'boolean'){
59931 rv = this.renderBool(val);
59933 return Roo.util.Format.htmlEncode(rv);
59936 getPropertyName : function(name){
59937 var pn = this.grid.propertyNames;
59938 return pn && pn[name] ? pn[name] : name;
59941 getCellEditor : function(colIndex, rowIndex){
59942 var p = this.store.getProperty(rowIndex);
59943 var n = p.data['name'], val = p.data['value'];
59945 if(typeof(this.grid.customEditors[n]) == 'string'){
59946 return this.editors[this.grid.customEditors[n]];
59948 if(typeof(this.grid.customEditors[n]) != 'undefined'){
59949 return this.grid.customEditors[n];
59951 if(val instanceof Date){
59952 return this.editors['date'];
59953 }else if(typeof val == 'number'){
59954 return this.editors['number'];
59955 }else if(typeof val == 'boolean'){
59956 return this.editors['boolean'];
59958 return this.editors['string'];
59964 * @class Roo.grid.PropertyGrid
59965 * @extends Roo.grid.EditorGrid
59966 * This class represents the interface of a component based property grid control.
59967 * <br><br>Usage:<pre><code>
59968 var grid = new Roo.grid.PropertyGrid("my-container-id", {
59976 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59977 * The container MUST have some type of size defined for the grid to fill. The container will be
59978 * automatically set to position relative if it isn't already.
59979 * @param {Object} config A config object that sets properties on this grid.
59981 Roo.grid.PropertyGrid = function(container, config){
59982 config = config || {};
59983 var store = new Roo.grid.PropertyStore(this);
59984 this.store = store;
59985 var cm = new Roo.grid.PropertyColumnModel(this, store);
59986 store.store.sort('name', 'ASC');
59987 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
59990 enableColLock:false,
59991 enableColumnMove:false,
59993 trackMouseOver: false,
59996 this.getGridEl().addClass('x-props-grid');
59997 this.lastEditRow = null;
59998 this.on('columnresize', this.onColumnResize, this);
60001 * @event beforepropertychange
60002 * Fires before a property changes (return false to stop?)
60003 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60004 * @param {String} id Record Id
60005 * @param {String} newval New Value
60006 * @param {String} oldval Old Value
60008 "beforepropertychange": true,
60010 * @event propertychange
60011 * Fires after a property changes
60012 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60013 * @param {String} id Record Id
60014 * @param {String} newval New Value
60015 * @param {String} oldval Old Value
60017 "propertychange": true
60019 this.customEditors = this.customEditors || {};
60021 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
60024 * @cfg {Object} customEditors map of colnames=> custom editors.
60025 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
60026 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
60027 * false disables editing of the field.
60031 * @cfg {Object} propertyNames map of property Names to their displayed value
60034 render : function(){
60035 Roo.grid.PropertyGrid.superclass.render.call(this);
60036 this.autoSize.defer(100, this);
60039 autoSize : function(){
60040 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
60042 this.view.fitColumns();
60046 onColumnResize : function(){
60047 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
60051 * Sets the data for the Grid
60052 * accepts a Key => Value object of all the elements avaiable.
60053 * @param {Object} data to appear in grid.
60055 setSource : function(source){
60056 this.store.setSource(source);
60060 * Gets all the data from the grid.
60061 * @return {Object} data data stored in grid
60063 getSource : function(){
60064 return this.store.getSource();
60073 * @class Roo.grid.Calendar
60074 * @extends Roo.util.Grid
60075 * This class extends the Grid to provide a calendar widget
60076 * <br><br>Usage:<pre><code>
60077 var grid = new Roo.grid.Calendar("my-container-id", {
60080 selModel: mySelectionModel,
60081 autoSizeColumns: true,
60082 monitorWindowResize: false,
60083 trackMouseOver: true
60084 eventstore : real data store..
60090 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60091 * The container MUST have some type of size defined for the grid to fill. The container will be
60092 * automatically set to position relative if it isn't already.
60093 * @param {Object} config A config object that sets properties on this grid.
60095 Roo.grid.Calendar = function(container, config){
60096 // initialize the container
60097 this.container = Roo.get(container);
60098 this.container.update("");
60099 this.container.setStyle("overflow", "hidden");
60100 this.container.addClass('x-grid-container');
60102 this.id = this.container.id;
60104 Roo.apply(this, config);
60105 // check and correct shorthanded configs
60109 for (var r = 0;r < 6;r++) {
60112 for (var c =0;c < 7;c++) {
60116 if (this.eventStore) {
60117 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60118 this.eventStore.on('load',this.onLoad, this);
60119 this.eventStore.on('beforeload',this.clearEvents, this);
60123 this.dataSource = new Roo.data.Store({
60124 proxy: new Roo.data.MemoryProxy(rows),
60125 reader: new Roo.data.ArrayReader({}, [
60126 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60129 this.dataSource.load();
60130 this.ds = this.dataSource;
60131 this.ds.xmodule = this.xmodule || false;
60134 var cellRender = function(v,x,r)
60136 return String.format(
60137 '<div class="fc-day fc-widget-content"><div>' +
60138 '<div class="fc-event-container"></div>' +
60139 '<div class="fc-day-number">{0}</div>'+
60141 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60142 '</div></div>', v);
60147 this.colModel = new Roo.grid.ColumnModel( [
60149 xtype: 'ColumnModel',
60151 dataIndex : 'weekday0',
60153 renderer : cellRender
60156 xtype: 'ColumnModel',
60158 dataIndex : 'weekday1',
60160 renderer : cellRender
60163 xtype: 'ColumnModel',
60165 dataIndex : 'weekday2',
60166 header : 'Tuesday',
60167 renderer : cellRender
60170 xtype: 'ColumnModel',
60172 dataIndex : 'weekday3',
60173 header : 'Wednesday',
60174 renderer : cellRender
60177 xtype: 'ColumnModel',
60179 dataIndex : 'weekday4',
60180 header : 'Thursday',
60181 renderer : cellRender
60184 xtype: 'ColumnModel',
60186 dataIndex : 'weekday5',
60188 renderer : cellRender
60191 xtype: 'ColumnModel',
60193 dataIndex : 'weekday6',
60194 header : 'Saturday',
60195 renderer : cellRender
60198 this.cm = this.colModel;
60199 this.cm.xmodule = this.xmodule || false;
60203 //this.selModel = new Roo.grid.CellSelectionModel();
60204 //this.sm = this.selModel;
60205 //this.selModel.init(this);
60209 this.container.setWidth(this.width);
60213 this.container.setHeight(this.height);
60220 * The raw click event for the entire grid.
60221 * @param {Roo.EventObject} e
60226 * The raw dblclick event for the entire grid.
60227 * @param {Roo.EventObject} e
60231 * @event contextmenu
60232 * The raw contextmenu event for the entire grid.
60233 * @param {Roo.EventObject} e
60235 "contextmenu" : true,
60238 * The raw mousedown event for the entire grid.
60239 * @param {Roo.EventObject} e
60241 "mousedown" : true,
60244 * The raw mouseup event for the entire grid.
60245 * @param {Roo.EventObject} e
60250 * The raw mouseover event for the entire grid.
60251 * @param {Roo.EventObject} e
60253 "mouseover" : true,
60256 * The raw mouseout event for the entire grid.
60257 * @param {Roo.EventObject} e
60262 * The raw keypress event for the entire grid.
60263 * @param {Roo.EventObject} e
60268 * The raw keydown event for the entire grid.
60269 * @param {Roo.EventObject} e
60277 * Fires when a cell is clicked
60278 * @param {Grid} this
60279 * @param {Number} rowIndex
60280 * @param {Number} columnIndex
60281 * @param {Roo.EventObject} e
60283 "cellclick" : true,
60285 * @event celldblclick
60286 * Fires when a cell is double clicked
60287 * @param {Grid} this
60288 * @param {Number} rowIndex
60289 * @param {Number} columnIndex
60290 * @param {Roo.EventObject} e
60292 "celldblclick" : true,
60295 * Fires when a row is clicked
60296 * @param {Grid} this
60297 * @param {Number} rowIndex
60298 * @param {Roo.EventObject} e
60302 * @event rowdblclick
60303 * Fires when a row is double clicked
60304 * @param {Grid} this
60305 * @param {Number} rowIndex
60306 * @param {Roo.EventObject} e
60308 "rowdblclick" : true,
60310 * @event headerclick
60311 * Fires when a header is clicked
60312 * @param {Grid} this
60313 * @param {Number} columnIndex
60314 * @param {Roo.EventObject} e
60316 "headerclick" : true,
60318 * @event headerdblclick
60319 * Fires when a header cell is double clicked
60320 * @param {Grid} this
60321 * @param {Number} columnIndex
60322 * @param {Roo.EventObject} e
60324 "headerdblclick" : true,
60326 * @event rowcontextmenu
60327 * Fires when a row is right clicked
60328 * @param {Grid} this
60329 * @param {Number} rowIndex
60330 * @param {Roo.EventObject} e
60332 "rowcontextmenu" : true,
60334 * @event cellcontextmenu
60335 * Fires when a cell is right clicked
60336 * @param {Grid} this
60337 * @param {Number} rowIndex
60338 * @param {Number} cellIndex
60339 * @param {Roo.EventObject} e
60341 "cellcontextmenu" : true,
60343 * @event headercontextmenu
60344 * Fires when a header is right clicked
60345 * @param {Grid} this
60346 * @param {Number} columnIndex
60347 * @param {Roo.EventObject} e
60349 "headercontextmenu" : true,
60351 * @event bodyscroll
60352 * Fires when the body element is scrolled
60353 * @param {Number} scrollLeft
60354 * @param {Number} scrollTop
60356 "bodyscroll" : true,
60358 * @event columnresize
60359 * Fires when the user resizes a column
60360 * @param {Number} columnIndex
60361 * @param {Number} newSize
60363 "columnresize" : true,
60365 * @event columnmove
60366 * Fires when the user moves a column
60367 * @param {Number} oldIndex
60368 * @param {Number} newIndex
60370 "columnmove" : true,
60373 * Fires when row(s) start being dragged
60374 * @param {Grid} this
60375 * @param {Roo.GridDD} dd The drag drop object
60376 * @param {event} e The raw browser event
60378 "startdrag" : true,
60381 * Fires when a drag operation is complete
60382 * @param {Grid} this
60383 * @param {Roo.GridDD} dd The drag drop object
60384 * @param {event} e The raw browser event
60389 * Fires when dragged row(s) are dropped on a valid DD target
60390 * @param {Grid} this
60391 * @param {Roo.GridDD} dd The drag drop object
60392 * @param {String} targetId The target drag drop object
60393 * @param {event} e The raw browser event
60398 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60399 * @param {Grid} this
60400 * @param {Roo.GridDD} dd The drag drop object
60401 * @param {String} targetId The target drag drop object
60402 * @param {event} e The raw browser event
60407 * Fires when the dragged row(s) first cross another DD target while being dragged
60408 * @param {Grid} this
60409 * @param {Roo.GridDD} dd The drag drop object
60410 * @param {String} targetId The target drag drop object
60411 * @param {event} e The raw browser event
60413 "dragenter" : true,
60416 * Fires when the dragged row(s) leave another DD target while being dragged
60417 * @param {Grid} this
60418 * @param {Roo.GridDD} dd The drag drop object
60419 * @param {String} targetId The target drag drop object
60420 * @param {event} e The raw browser event
60425 * Fires when a row is rendered, so you can change add a style to it.
60426 * @param {GridView} gridview The grid view
60427 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60433 * Fires when the grid is rendered
60434 * @param {Grid} grid
60439 * Fires when a date is selected
60440 * @param {DatePicker} this
60441 * @param {Date} date The selected date
60445 * @event monthchange
60446 * Fires when the displayed month changes
60447 * @param {DatePicker} this
60448 * @param {Date} date The selected month
60450 'monthchange': true,
60452 * @event evententer
60453 * Fires when mouse over an event
60454 * @param {Calendar} this
60455 * @param {event} Event
60457 'evententer': true,
60459 * @event eventleave
60460 * Fires when the mouse leaves an
60461 * @param {Calendar} this
60464 'eventleave': true,
60466 * @event eventclick
60467 * Fires when the mouse click an
60468 * @param {Calendar} this
60471 'eventclick': true,
60473 * @event eventrender
60474 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60475 * @param {Calendar} this
60476 * @param {data} data to be modified
60478 'eventrender': true
60482 Roo.grid.Grid.superclass.constructor.call(this);
60483 this.on('render', function() {
60484 this.view.el.addClass('x-grid-cal');
60486 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60490 if (!Roo.grid.Calendar.style) {
60491 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60494 '.x-grid-cal .x-grid-col' : {
60495 height: 'auto !important',
60496 'vertical-align': 'top'
60498 '.x-grid-cal .fc-event-hori' : {
60509 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60511 * @cfg {Store} eventStore The store that loads events.
60516 activeDate : false,
60519 monitorWindowResize : false,
60522 resizeColumns : function() {
60523 var col = (this.view.el.getWidth() / 7) - 3;
60524 // loop through cols, and setWidth
60525 for(var i =0 ; i < 7 ; i++){
60526 this.cm.setColumnWidth(i, col);
60529 setDate :function(date) {
60531 Roo.log('setDate?');
60533 this.resizeColumns();
60534 var vd = this.activeDate;
60535 this.activeDate = date;
60536 // if(vd && this.el){
60537 // var t = date.getTime();
60538 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60539 // Roo.log('using add remove');
60541 // this.fireEvent('monthchange', this, date);
60543 // this.cells.removeClass("fc-state-highlight");
60544 // this.cells.each(function(c){
60545 // if(c.dateValue == t){
60546 // c.addClass("fc-state-highlight");
60547 // setTimeout(function(){
60548 // try{c.dom.firstChild.focus();}catch(e){}
60558 var days = date.getDaysInMonth();
60560 var firstOfMonth = date.getFirstDateOfMonth();
60561 var startingPos = firstOfMonth.getDay()-this.startDay;
60563 if(startingPos < this.startDay){
60567 var pm = date.add(Date.MONTH, -1);
60568 var prevStart = pm.getDaysInMonth()-startingPos;
60572 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60574 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60575 //this.cells.addClassOnOver('fc-state-hover');
60577 var cells = this.cells.elements;
60578 var textEls = this.textNodes;
60580 //Roo.each(cells, function(cell){
60581 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60584 days += startingPos;
60586 // convert everything to numbers so it's fast
60587 var day = 86400000;
60588 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60591 //Roo.log(prevStart);
60593 var today = new Date().clearTime().getTime();
60594 var sel = date.clearTime().getTime();
60595 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60596 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60597 var ddMatch = this.disabledDatesRE;
60598 var ddText = this.disabledDatesText;
60599 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60600 var ddaysText = this.disabledDaysText;
60601 var format = this.format;
60603 var setCellClass = function(cal, cell){
60605 //Roo.log('set Cell Class');
60607 var t = d.getTime();
60612 cell.dateValue = t;
60614 cell.className += " fc-today";
60615 cell.className += " fc-state-highlight";
60616 cell.title = cal.todayText;
60619 // disable highlight in other month..
60620 cell.className += " fc-state-highlight";
60625 //cell.className = " fc-state-disabled";
60626 cell.title = cal.minText;
60630 //cell.className = " fc-state-disabled";
60631 cell.title = cal.maxText;
60635 if(ddays.indexOf(d.getDay()) != -1){
60636 // cell.title = ddaysText;
60637 // cell.className = " fc-state-disabled";
60640 if(ddMatch && format){
60641 var fvalue = d.dateFormat(format);
60642 if(ddMatch.test(fvalue)){
60643 cell.title = ddText.replace("%0", fvalue);
60644 cell.className = " fc-state-disabled";
60648 if (!cell.initialClassName) {
60649 cell.initialClassName = cell.dom.className;
60652 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60657 for(; i < startingPos; i++) {
60658 cells[i].dayName = (++prevStart);
60659 Roo.log(textEls[i]);
60660 d.setDate(d.getDate()+1);
60662 //cells[i].className = "fc-past fc-other-month";
60663 setCellClass(this, cells[i]);
60668 for(; i < days; i++){
60669 intDay = i - startingPos + 1;
60670 cells[i].dayName = (intDay);
60671 d.setDate(d.getDate()+1);
60673 cells[i].className = ''; // "x-date-active";
60674 setCellClass(this, cells[i]);
60678 for(; i < 42; i++) {
60679 //textEls[i].innerHTML = (++extraDays);
60681 d.setDate(d.getDate()+1);
60682 cells[i].dayName = (++extraDays);
60683 cells[i].className = "fc-future fc-other-month";
60684 setCellClass(this, cells[i]);
60687 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60689 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60691 // this will cause all the cells to mis
60694 for (var r = 0;r < 6;r++) {
60695 for (var c =0;c < 7;c++) {
60696 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60700 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60701 for(i=0;i<cells.length;i++) {
60703 this.cells.elements[i].dayName = cells[i].dayName ;
60704 this.cells.elements[i].className = cells[i].className;
60705 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
60706 this.cells.elements[i].title = cells[i].title ;
60707 this.cells.elements[i].dateValue = cells[i].dateValue ;
60713 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
60714 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
60716 ////if(totalRows != 6){
60717 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
60718 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
60721 this.fireEvent('monthchange', this, date);
60726 * Returns the grid's SelectionModel.
60727 * @return {SelectionModel}
60729 getSelectionModel : function(){
60730 if(!this.selModel){
60731 this.selModel = new Roo.grid.CellSelectionModel();
60733 return this.selModel;
60737 this.eventStore.load()
60743 findCell : function(dt) {
60744 dt = dt.clearTime().getTime();
60746 this.cells.each(function(c){
60747 //Roo.log("check " +c.dateValue + '?=' + dt);
60748 if(c.dateValue == dt){
60758 findCells : function(rec) {
60759 var s = rec.data.start_dt.clone().clearTime().getTime();
60761 var e= rec.data.end_dt.clone().clearTime().getTime();
60764 this.cells.each(function(c){
60765 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
60767 if(c.dateValue > e){
60770 if(c.dateValue < s){
60779 findBestRow: function(cells)
60783 for (var i =0 ; i < cells.length;i++) {
60784 ret = Math.max(cells[i].rows || 0,ret);
60791 addItem : function(rec)
60793 // look for vertical location slot in
60794 var cells = this.findCells(rec);
60796 rec.row = this.findBestRow(cells);
60798 // work out the location.
60802 for(var i =0; i < cells.length; i++) {
60810 if (crow.start.getY() == cells[i].getY()) {
60812 crow.end = cells[i];
60828 for (var i = 0; i < cells.length;i++) {
60829 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
60836 clearEvents: function() {
60838 if (!this.eventStore.getCount()) {
60841 // reset number of rows in cells.
60842 Roo.each(this.cells.elements, function(c){
60846 this.eventStore.each(function(e) {
60847 this.clearEvent(e);
60852 clearEvent : function(ev)
60855 Roo.each(ev.els, function(el) {
60856 el.un('mouseenter' ,this.onEventEnter, this);
60857 el.un('mouseleave' ,this.onEventLeave, this);
60865 renderEvent : function(ev,ctr) {
60867 ctr = this.view.el.select('.fc-event-container',true).first();
60871 this.clearEvent(ev);
60877 var cells = ev.cells;
60878 var rows = ev.rows;
60879 this.fireEvent('eventrender', this, ev);
60881 for(var i =0; i < rows.length; i++) {
60885 cls += ' fc-event-start';
60887 if ((i+1) == rows.length) {
60888 cls += ' fc-event-end';
60891 //Roo.log(ev.data);
60892 // how many rows should it span..
60893 var cg = this.eventTmpl.append(ctr,Roo.apply({
60896 }, ev.data) , true);
60899 cg.on('mouseenter' ,this.onEventEnter, this, ev);
60900 cg.on('mouseleave' ,this.onEventLeave, this, ev);
60901 cg.on('click', this.onEventClick, this, ev);
60905 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
60906 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
60909 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
60910 cg.setWidth(ebox.right - sbox.x -2);
60914 renderEvents: function()
60916 // first make sure there is enough space..
60918 if (!this.eventTmpl) {
60919 this.eventTmpl = new Roo.Template(
60920 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
60921 '<div class="fc-event-inner">' +
60922 '<span class="fc-event-time">{time}</span>' +
60923 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
60925 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
60933 this.cells.each(function(c) {
60934 //Roo.log(c.select('.fc-day-content div',true).first());
60935 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
60938 var ctr = this.view.el.select('.fc-event-container',true).first();
60941 this.eventStore.each(function(ev){
60943 this.renderEvent(ev);
60947 this.view.layout();
60951 onEventEnter: function (e, el,event,d) {
60952 this.fireEvent('evententer', this, el, event);
60955 onEventLeave: function (e, el,event,d) {
60956 this.fireEvent('eventleave', this, el, event);
60959 onEventClick: function (e, el,event,d) {
60960 this.fireEvent('eventclick', this, el, event);
60963 onMonthChange: function () {
60967 onLoad: function () {
60969 //Roo.log('calendar onload');
60971 if(this.eventStore.getCount() > 0){
60975 this.eventStore.each(function(d){
60980 if (typeof(add.end_dt) == 'undefined') {
60981 Roo.log("Missing End time in calendar data: ");
60985 if (typeof(add.start_dt) == 'undefined') {
60986 Roo.log("Missing Start time in calendar data: ");
60990 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
60991 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
60992 add.id = add.id || d.id;
60993 add.title = add.title || '??';
61001 this.renderEvents();
61011 render : function ()
61015 if (!this.view.el.hasClass('course-timesheet')) {
61016 this.view.el.addClass('course-timesheet');
61018 if (this.tsStyle) {
61023 Roo.log(_this.grid.view.el.getWidth());
61026 this.tsStyle = Roo.util.CSS.createStyleSheet({
61027 '.course-timesheet .x-grid-row' : {
61030 '.x-grid-row td' : {
61031 'vertical-align' : 0
61033 '.course-edit-link' : {
61035 'text-overflow' : 'ellipsis',
61036 'overflow' : 'hidden',
61037 'white-space' : 'nowrap',
61038 'cursor' : 'pointer'
61043 '.de-act-sup-link' : {
61044 'color' : 'purple',
61045 'text-decoration' : 'line-through'
61049 'text-decoration' : 'line-through'
61051 '.course-timesheet .course-highlight' : {
61052 'border-top-style': 'dashed !important',
61053 'border-bottom-bottom': 'dashed !important'
61055 '.course-timesheet .course-item' : {
61056 'font-family' : 'tahoma, arial, helvetica',
61057 'font-size' : '11px',
61058 'overflow' : 'hidden',
61059 'padding-left' : '10px',
61060 'padding-right' : '10px',
61061 'padding-top' : '10px'
61069 monitorWindowResize : false,
61070 cellrenderer : function(v,x,r)
61075 xtype: 'CellSelectionModel',
61082 beforeload : function (_self, options)
61084 options.params = options.params || {};
61085 options.params._month = _this.monthField.getValue();
61086 options.params.limit = 9999;
61087 options.params['sort'] = 'when_dt';
61088 options.params['dir'] = 'ASC';
61089 this.proxy.loadResponse = this.loadResponse;
61091 //this.addColumns();
61093 load : function (_self, records, options)
61095 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
61096 // if you click on the translation.. you can edit it...
61097 var el = Roo.get(this);
61098 var id = el.dom.getAttribute('data-id');
61099 var d = el.dom.getAttribute('data-date');
61100 var t = el.dom.getAttribute('data-time');
61101 //var id = this.child('span').dom.textContent;
61104 Pman.Dialog.CourseCalendar.show({
61108 productitem_active : id ? 1 : 0
61110 _this.grid.ds.load({});
61115 _this.panel.fireEvent('resize', [ '', '' ]);
61118 loadResponse : function(o, success, response){
61119 // this is overridden on before load..
61121 Roo.log("our code?");
61122 //Roo.log(success);
61123 //Roo.log(response)
61124 delete this.activeRequest;
61126 this.fireEvent("loadexception", this, o, response);
61127 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61132 result = o.reader.read(response);
61134 Roo.log("load exception?");
61135 this.fireEvent("loadexception", this, o, response, e);
61136 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61139 Roo.log("ready...");
61140 // loop through result.records;
61141 // and set this.tdate[date] = [] << array of records..
61143 Roo.each(result.records, function(r){
61145 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61146 _this.tdata[r.data.when_dt.format('j')] = [];
61148 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61151 //Roo.log(_this.tdata);
61153 result.records = [];
61154 result.totalRecords = 6;
61156 // let's generate some duumy records for the rows.
61157 //var st = _this.dateField.getValue();
61159 // work out monday..
61160 //st = st.add(Date.DAY, -1 * st.format('w'));
61162 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61164 var firstOfMonth = date.getFirstDayOfMonth();
61165 var days = date.getDaysInMonth();
61167 var firstAdded = false;
61168 for (var i = 0; i < result.totalRecords ; i++) {
61169 //var d= st.add(Date.DAY, i);
61172 for(var w = 0 ; w < 7 ; w++){
61173 if(!firstAdded && firstOfMonth != w){
61180 var dd = (d > 0 && d < 10) ? "0"+d : d;
61181 row['weekday'+w] = String.format(
61182 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61183 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61185 date.format('Y-m-')+dd
61188 if(typeof(_this.tdata[d]) != 'undefined'){
61189 Roo.each(_this.tdata[d], function(r){
61193 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61194 if(r.parent_id*1>0){
61195 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61198 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61199 deactive = 'de-act-link';
61202 row['weekday'+w] += String.format(
61203 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61205 r.product_id_name, //1
61206 r.when_dt.format('h:ia'), //2
61216 // only do this if something added..
61218 result.records.push(_this.grid.dataSource.reader.newRow(row));
61222 // push it twice. (second one with an hour..
61226 this.fireEvent("load", this, o, o.request.arg);
61227 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61229 sortInfo : {field: 'when_dt', direction : 'ASC' },
61231 xtype: 'HttpProxy',
61234 url : baseURL + '/Roo/Shop_course.php'
61237 xtype: 'JsonReader',
61254 'name': 'parent_id',
61258 'name': 'product_id',
61262 'name': 'productitem_id',
61280 click : function (_self, e)
61282 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61283 sd.setMonth(sd.getMonth()-1);
61284 _this.monthField.setValue(sd.format('Y-m-d'));
61285 _this.grid.ds.load({});
61291 xtype: 'Separator',
61295 xtype: 'MonthField',
61298 render : function (_self)
61300 _this.monthField = _self;
61301 // _this.monthField.set today
61303 select : function (combo, date)
61305 _this.grid.ds.load({});
61308 value : (function() { return new Date(); })()
61311 xtype: 'Separator',
61317 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61327 click : function (_self, e)
61329 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61330 sd.setMonth(sd.getMonth()+1);
61331 _this.monthField.setValue(sd.format('Y-m-d'));
61332 _this.grid.ds.load({});
61345 * Ext JS Library 1.1.1
61346 * Copyright(c) 2006-2007, Ext JS, LLC.
61348 * Originally Released Under LGPL - original licence link has changed is not relivant.
61351 * <script type="text/javascript">
61355 * @class Roo.LoadMask
61356 * A simple utility class for generically masking elements while loading data. If the element being masked has
61357 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61358 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61359 * element's UpdateManager load indicator and will be destroyed after the initial load.
61361 * Create a new LoadMask
61362 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61363 * @param {Object} config The config object
61365 Roo.LoadMask = function(el, config){
61366 this.el = Roo.get(el);
61367 Roo.apply(this, config);
61369 this.store.on('beforeload', this.onBeforeLoad, this);
61370 this.store.on('load', this.onLoad, this);
61371 this.store.on('loadexception', this.onLoadException, this);
61372 this.removeMask = false;
61374 var um = this.el.getUpdateManager();
61375 um.showLoadIndicator = false; // disable the default indicator
61376 um.on('beforeupdate', this.onBeforeLoad, this);
61377 um.on('update', this.onLoad, this);
61378 um.on('failure', this.onLoad, this);
61379 this.removeMask = true;
61383 Roo.LoadMask.prototype = {
61385 * @cfg {Boolean} removeMask
61386 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61387 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61390 * @cfg {String} msg
61391 * The text to display in a centered loading message box (defaults to 'Loading...')
61393 msg : 'Loading...',
61395 * @cfg {String} msgCls
61396 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61398 msgCls : 'x-mask-loading',
61401 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61407 * Disables the mask to prevent it from being displayed
61409 disable : function(){
61410 this.disabled = true;
61414 * Enables the mask so that it can be displayed
61416 enable : function(){
61417 this.disabled = false;
61420 onLoadException : function()
61422 Roo.log(arguments);
61424 if (typeof(arguments[3]) != 'undefined') {
61425 Roo.MessageBox.alert("Error loading",arguments[3]);
61429 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61430 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61437 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61440 onLoad : function()
61442 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61446 onBeforeLoad : function(){
61447 if(!this.disabled){
61448 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61453 destroy : function(){
61455 this.store.un('beforeload', this.onBeforeLoad, this);
61456 this.store.un('load', this.onLoad, this);
61457 this.store.un('loadexception', this.onLoadException, this);
61459 var um = this.el.getUpdateManager();
61460 um.un('beforeupdate', this.onBeforeLoad, this);
61461 um.un('update', this.onLoad, this);
61462 um.un('failure', this.onLoad, this);
61467 * Ext JS Library 1.1.1
61468 * Copyright(c) 2006-2007, Ext JS, LLC.
61470 * Originally Released Under LGPL - original licence link has changed is not relivant.
61473 * <script type="text/javascript">
61478 * @class Roo.XTemplate
61479 * @extends Roo.Template
61480 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61482 var t = new Roo.XTemplate(
61483 '<select name="{name}">',
61484 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61488 // then append, applying the master template values
61491 * Supported features:
61496 {a_variable} - output encoded.
61497 {a_variable.format:("Y-m-d")} - call a method on the variable
61498 {a_variable:raw} - unencoded output
61499 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61500 {a_variable:this.method_on_template(...)} - call a method on the template object.
61505 <tpl for="a_variable or condition.."></tpl>
61506 <tpl if="a_variable or condition"></tpl>
61507 <tpl exec="some javascript"></tpl>
61508 <tpl name="named_template"></tpl> (experimental)
61510 <tpl for="."></tpl> - just iterate the property..
61511 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61515 Roo.XTemplate = function()
61517 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61524 Roo.extend(Roo.XTemplate, Roo.Template, {
61527 * The various sub templates
61532 * basic tag replacing syntax
61535 * // you can fake an object call by doing this
61539 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61542 * compile the template
61544 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61547 compile: function()
61551 s = ['<tpl>', s, '</tpl>'].join('');
61553 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61554 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61555 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61556 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61557 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61562 while(true == !!(m = s.match(re))){
61563 var forMatch = m[0].match(nameRe),
61564 ifMatch = m[0].match(ifRe),
61565 execMatch = m[0].match(execRe),
61566 namedMatch = m[0].match(namedRe),
61571 name = forMatch && forMatch[1] ? forMatch[1] : '';
61574 // if - puts fn into test..
61575 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61577 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61582 // exec - calls a function... returns empty if true is returned.
61583 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61585 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61593 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61594 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61595 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61598 var uid = namedMatch ? namedMatch[1] : id;
61602 id: namedMatch ? namedMatch[1] : id,
61609 s = s.replace(m[0], '');
61611 s = s.replace(m[0], '{xtpl'+ id + '}');
61616 for(var i = tpls.length-1; i >= 0; --i){
61617 this.compileTpl(tpls[i]);
61618 this.tpls[tpls[i].id] = tpls[i];
61620 this.master = tpls[tpls.length-1];
61624 * same as applyTemplate, except it's done to one of the subTemplates
61625 * when using named templates, you can do:
61627 * var str = pl.applySubTemplate('your-name', values);
61630 * @param {Number} id of the template
61631 * @param {Object} values to apply to template
61632 * @param {Object} parent (normaly the instance of this object)
61634 applySubTemplate : function(id, values, parent)
61638 var t = this.tpls[id];
61642 if(t.test && !t.test.call(this, values, parent)){
61646 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61647 Roo.log(e.toString());
61653 if(t.exec && t.exec.call(this, values, parent)){
61657 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61658 Roo.log(e.toString());
61663 var vs = t.target ? t.target.call(this, values, parent) : values;
61664 parent = t.target ? values : parent;
61665 if(t.target && vs instanceof Array){
61667 for(var i = 0, len = vs.length; i < len; i++){
61668 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61670 return buf.join('');
61672 return t.compiled.call(this, vs, parent);
61674 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61675 Roo.log(e.toString());
61676 Roo.log(t.compiled);
61681 compileTpl : function(tpl)
61683 var fm = Roo.util.Format;
61684 var useF = this.disableFormats !== true;
61685 var sep = Roo.isGecko ? "+" : ",";
61686 var undef = function(str) {
61687 Roo.log("Property not found :" + str);
61691 var fn = function(m, name, format, args)
61693 //Roo.log(arguments);
61694 args = args ? args.replace(/\\'/g,"'") : args;
61695 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61696 if (typeof(format) == 'undefined') {
61697 format= 'htmlEncode';
61699 if (format == 'raw' ) {
61703 if(name.substr(0, 4) == 'xtpl'){
61704 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
61707 // build an array of options to determine if value is undefined..
61709 // basically get 'xxxx.yyyy' then do
61710 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
61711 // (function () { Roo.log("Property not found"); return ''; })() :
61716 Roo.each(name.split('.'), function(st) {
61717 lookfor += (lookfor.length ? '.': '') + st;
61718 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
61721 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
61724 if(format && useF){
61726 args = args ? ',' + args : "";
61728 if(format.substr(0, 5) != "this."){
61729 format = "fm." + format + '(';
61731 format = 'this.call("'+ format.substr(5) + '", ';
61735 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
61739 // called with xxyx.yuu:(test,test)
61741 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
61743 // raw.. - :raw modifier..
61744 return "'"+ sep + udef_st + name + ")"+sep+"'";
61748 // branched to use + in gecko and [].join() in others
61750 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
61751 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
61754 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
61755 body.push(tpl.body.replace(/(\r\n|\n)/g,
61756 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
61757 body.push("'].join('');};};");
61758 body = body.join('');
61761 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
61763 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
61769 applyTemplate : function(values){
61770 return this.master.compiled.call(this, values, {});
61771 //var s = this.subs;
61774 apply : function(){
61775 return this.applyTemplate.apply(this, arguments);
61780 Roo.XTemplate.from = function(el){
61781 el = Roo.getDom(el);
61782 return new Roo.XTemplate(el.value || el.innerHTML);