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 this.fireEvent('dblclick', this, event);
8253 //action on double tap goes below
8258 * Removes an event handler from this element
8259 * @param {String} eventName the type of event to remove
8260 * @param {Function} fn the method the event invokes
8261 * @return {Roo.Element} this
8263 removeListener : function(eventName, fn){
8264 Roo.EventManager.removeListener(this.dom, eventName, fn);
8269 * Removes all previous added listeners from this element
8270 * @return {Roo.Element} this
8272 removeAllListeners : function(){
8273 E.purgeElement(this.dom);
8277 relayEvent : function(eventName, observable){
8278 this.on(eventName, function(e){
8279 observable.fireEvent(eventName, e);
8284 * Set the opacity of the element
8285 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8286 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8287 * @return {Roo.Element} this
8289 setOpacity : function(opacity, animate){
8291 var s = this.dom.style;
8294 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8295 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8297 s.opacity = opacity;
8300 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8306 * Gets the left X coordinate
8307 * @param {Boolean} local True to get the local css position instead of page coordinate
8310 getLeft : function(local){
8314 return parseInt(this.getStyle("left"), 10) || 0;
8319 * Gets the right X coordinate of the element (element X position + element width)
8320 * @param {Boolean} local True to get the local css position instead of page coordinate
8323 getRight : function(local){
8325 return this.getX() + this.getWidth();
8327 return (this.getLeft(true) + this.getWidth()) || 0;
8332 * Gets the top Y coordinate
8333 * @param {Boolean} local True to get the local css position instead of page coordinate
8336 getTop : function(local) {
8340 return parseInt(this.getStyle("top"), 10) || 0;
8345 * Gets the bottom Y coordinate of the element (element Y position + element height)
8346 * @param {Boolean} local True to get the local css position instead of page coordinate
8349 getBottom : function(local){
8351 return this.getY() + this.getHeight();
8353 return (this.getTop(true) + this.getHeight()) || 0;
8358 * Initializes positioning on this element. If a desired position is not passed, it will make the
8359 * the element positioned relative IF it is not already positioned.
8360 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8361 * @param {Number} zIndex (optional) The zIndex to apply
8362 * @param {Number} x (optional) Set the page X position
8363 * @param {Number} y (optional) Set the page Y position
8365 position : function(pos, zIndex, x, y){
8367 if(this.getStyle('position') == 'static'){
8368 this.setStyle('position', 'relative');
8371 this.setStyle("position", pos);
8374 this.setStyle("z-index", zIndex);
8376 if(x !== undefined && y !== undefined){
8378 }else if(x !== undefined){
8380 }else if(y !== undefined){
8386 * Clear positioning back to the default when the document was loaded
8387 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8388 * @return {Roo.Element} this
8390 clearPositioning : function(value){
8398 "position" : "static"
8404 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8405 * snapshot before performing an update and then restoring the element.
8408 getPositioning : function(){
8409 var l = this.getStyle("left");
8410 var t = this.getStyle("top");
8412 "position" : this.getStyle("position"),
8414 "right" : l ? "" : this.getStyle("right"),
8416 "bottom" : t ? "" : this.getStyle("bottom"),
8417 "z-index" : this.getStyle("z-index")
8422 * Gets the width of the border(s) for the specified side(s)
8423 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8424 * passing lr would get the border (l)eft width + the border (r)ight width.
8425 * @return {Number} The width of the sides passed added together
8427 getBorderWidth : function(side){
8428 return this.addStyles(side, El.borders);
8432 * Gets the width of the padding(s) for the specified side(s)
8433 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8434 * passing lr would get the padding (l)eft + the padding (r)ight.
8435 * @return {Number} The padding of the sides passed added together
8437 getPadding : function(side){
8438 return this.addStyles(side, El.paddings);
8442 * Set positioning with an object returned by getPositioning().
8443 * @param {Object} posCfg
8444 * @return {Roo.Element} this
8446 setPositioning : function(pc){
8447 this.applyStyles(pc);
8448 if(pc.right == "auto"){
8449 this.dom.style.right = "";
8451 if(pc.bottom == "auto"){
8452 this.dom.style.bottom = "";
8458 fixDisplay : function(){
8459 if(this.getStyle("display") == "none"){
8460 this.setStyle("visibility", "hidden");
8461 this.setStyle("display", this.originalDisplay); // first try reverting to default
8462 if(this.getStyle("display") == "none"){ // if that fails, default to block
8463 this.setStyle("display", "block");
8469 * Quick set left and top adding default units
8470 * @param {String} left The left CSS property value
8471 * @param {String} top The top CSS property value
8472 * @return {Roo.Element} this
8474 setLeftTop : function(left, top){
8475 this.dom.style.left = this.addUnits(left);
8476 this.dom.style.top = this.addUnits(top);
8481 * Move this element relative to its current position.
8482 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8483 * @param {Number} distance How far to move the element in pixels
8484 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8485 * @return {Roo.Element} this
8487 move : function(direction, distance, animate){
8488 var xy = this.getXY();
8489 direction = direction.toLowerCase();
8493 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8497 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8502 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8507 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8514 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8515 * @return {Roo.Element} this
8518 if(!this.isClipped){
8519 this.isClipped = true;
8520 this.originalClip = {
8521 "o": this.getStyle("overflow"),
8522 "x": this.getStyle("overflow-x"),
8523 "y": this.getStyle("overflow-y")
8525 this.setStyle("overflow", "hidden");
8526 this.setStyle("overflow-x", "hidden");
8527 this.setStyle("overflow-y", "hidden");
8533 * Return clipping (overflow) to original clipping before clip() was called
8534 * @return {Roo.Element} this
8536 unclip : function(){
8538 this.isClipped = false;
8539 var o = this.originalClip;
8540 if(o.o){this.setStyle("overflow", o.o);}
8541 if(o.x){this.setStyle("overflow-x", o.x);}
8542 if(o.y){this.setStyle("overflow-y", o.y);}
8549 * Gets the x,y coordinates specified by the anchor position on the element.
8550 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8551 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8552 * {width: (target width), height: (target height)} (defaults to the element's current size)
8553 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8554 * @return {Array} [x, y] An array containing the element's x and y coordinates
8556 getAnchorXY : function(anchor, local, s){
8557 //Passing a different size is useful for pre-calculating anchors,
8558 //especially for anchored animations that change the el size.
8560 var w, h, vp = false;
8563 if(d == document.body || d == document){
8565 w = D.getViewWidth(); h = D.getViewHeight();
8567 w = this.getWidth(); h = this.getHeight();
8570 w = s.width; h = s.height;
8572 var x = 0, y = 0, r = Math.round;
8573 switch((anchor || "tl").toLowerCase()){
8615 var sc = this.getScroll();
8616 return [x + sc.left, y + sc.top];
8618 //Add the element's offset xy
8619 var o = this.getXY();
8620 return [x+o[0], y+o[1]];
8624 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8625 * supported position values.
8626 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8627 * @param {String} position The position to align to.
8628 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8629 * @return {Array} [x, y]
8631 getAlignToXY : function(el, p, o)
8636 throw "Element.alignTo with an element that doesn't exist";
8638 var c = false; //constrain to viewport
8639 var p1 = "", p2 = "";
8646 }else if(p.indexOf("-") == -1){
8649 p = p.toLowerCase();
8650 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8652 throw "Element.alignTo with an invalid alignment " + p;
8654 p1 = m[1]; p2 = m[2]; c = !!m[3];
8656 //Subtract the aligned el's internal xy from the target's offset xy
8657 //plus custom offset to get the aligned el's new offset xy
8658 var a1 = this.getAnchorXY(p1, true);
8659 var a2 = el.getAnchorXY(p2, false);
8660 var x = a2[0] - a1[0] + o[0];
8661 var y = a2[1] - a1[1] + o[1];
8663 //constrain the aligned el to viewport if necessary
8664 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8665 // 5px of margin for ie
8666 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8668 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8669 //perpendicular to the vp border, allow the aligned el to slide on that border,
8670 //otherwise swap the aligned el to the opposite border of the target.
8671 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8672 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8673 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8674 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8677 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8678 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8680 if((x+w) > dw + scrollX){
8681 x = swapX ? r.left-w : dw+scrollX-w;
8684 x = swapX ? r.right : scrollX;
8686 if((y+h) > dh + scrollY){
8687 y = swapY ? r.top-h : dh+scrollY-h;
8690 y = swapY ? r.bottom : scrollY;
8697 getConstrainToXY : function(){
8698 var os = {top:0, left:0, bottom:0, right: 0};
8700 return function(el, local, offsets, proposedXY){
8702 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8704 var vw, vh, vx = 0, vy = 0;
8705 if(el.dom == document.body || el.dom == document){
8706 vw = Roo.lib.Dom.getViewWidth();
8707 vh = Roo.lib.Dom.getViewHeight();
8709 vw = el.dom.clientWidth;
8710 vh = el.dom.clientHeight;
8712 var vxy = el.getXY();
8718 var s = el.getScroll();
8720 vx += offsets.left + s.left;
8721 vy += offsets.top + s.top;
8723 vw -= offsets.right;
8724 vh -= offsets.bottom;
8729 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8730 var x = xy[0], y = xy[1];
8731 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8733 // only move it if it needs it
8736 // first validate right/bottom
8745 // then make sure top/left isn't negative
8754 return moved ? [x, y] : false;
8759 adjustForConstraints : function(xy, parent, offsets){
8760 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8764 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8765 * document it aligns it to the viewport.
8766 * The position parameter is optional, and can be specified in any one of the following formats:
8768 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8769 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8770 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8771 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8772 * <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
8773 * element's anchor point, and the second value is used as the target's anchor point.</li>
8775 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8776 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8777 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8778 * that specified in order to enforce the viewport constraints.
8779 * Following are all of the supported anchor positions:
8782 ----- -----------------------------
8783 tl The top left corner (default)
8784 t The center of the top edge
8785 tr The top right corner
8786 l The center of the left edge
8787 c In the center of the element
8788 r The center of the right edge
8789 bl The bottom left corner
8790 b The center of the bottom edge
8791 br The bottom right corner
8795 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8796 el.alignTo("other-el");
8798 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8799 el.alignTo("other-el", "tr?");
8801 // align the bottom right corner of el with the center left edge of other-el
8802 el.alignTo("other-el", "br-l?");
8804 // align the center of el with the bottom left corner of other-el and
8805 // adjust the x position by -6 pixels (and the y position by 0)
8806 el.alignTo("other-el", "c-bl", [-6, 0]);
8808 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8809 * @param {String} position The position to align to.
8810 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8811 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8812 * @return {Roo.Element} this
8814 alignTo : function(element, position, offsets, animate){
8815 var xy = this.getAlignToXY(element, position, offsets);
8816 this.setXY(xy, this.preanim(arguments, 3));
8821 * Anchors an element to another element and realigns it when the window is resized.
8822 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8823 * @param {String} position The position to align to.
8824 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8825 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8826 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8827 * is a number, it is used as the buffer delay (defaults to 50ms).
8828 * @param {Function} callback The function to call after the animation finishes
8829 * @return {Roo.Element} this
8831 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8832 var action = function(){
8833 this.alignTo(el, alignment, offsets, animate);
8834 Roo.callback(callback, this);
8836 Roo.EventManager.onWindowResize(action, this);
8837 var tm = typeof monitorScroll;
8838 if(tm != 'undefined'){
8839 Roo.EventManager.on(window, 'scroll', action, this,
8840 {buffer: tm == 'number' ? monitorScroll : 50});
8842 action.call(this); // align immediately
8846 * Clears any opacity settings from this element. Required in some cases for IE.
8847 * @return {Roo.Element} this
8849 clearOpacity : function(){
8850 if (window.ActiveXObject) {
8851 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8852 this.dom.style.filter = "";
8855 this.dom.style.opacity = "";
8856 this.dom.style["-moz-opacity"] = "";
8857 this.dom.style["-khtml-opacity"] = "";
8863 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8864 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8865 * @return {Roo.Element} this
8867 hide : function(animate){
8868 this.setVisible(false, this.preanim(arguments, 0));
8873 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8874 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8875 * @return {Roo.Element} this
8877 show : function(animate){
8878 this.setVisible(true, this.preanim(arguments, 0));
8883 * @private Test if size has a unit, otherwise appends the default
8885 addUnits : function(size){
8886 return Roo.Element.addUnits(size, this.defaultUnit);
8890 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8891 * @return {Roo.Element} this
8893 beginMeasure : function(){
8895 if(el.offsetWidth || el.offsetHeight){
8896 return this; // offsets work already
8899 var p = this.dom, b = document.body; // start with this element
8900 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8901 var pe = Roo.get(p);
8902 if(pe.getStyle('display') == 'none'){
8903 changed.push({el: p, visibility: pe.getStyle("visibility")});
8904 p.style.visibility = "hidden";
8905 p.style.display = "block";
8909 this._measureChanged = changed;
8915 * Restores displays to before beginMeasure was called
8916 * @return {Roo.Element} this
8918 endMeasure : function(){
8919 var changed = this._measureChanged;
8921 for(var i = 0, len = changed.length; i < len; i++) {
8923 r.el.style.visibility = r.visibility;
8924 r.el.style.display = "none";
8926 this._measureChanged = null;
8932 * Update the innerHTML of this element, optionally searching for and processing scripts
8933 * @param {String} html The new HTML
8934 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8935 * @param {Function} callback For async script loading you can be noticed when the update completes
8936 * @return {Roo.Element} this
8938 update : function(html, loadScripts, callback){
8939 if(typeof html == "undefined"){
8942 if(loadScripts !== true){
8943 this.dom.innerHTML = html;
8944 if(typeof callback == "function"){
8952 html += '<span id="' + id + '"></span>';
8954 E.onAvailable(id, function(){
8955 var hd = document.getElementsByTagName("head")[0];
8956 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8957 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8958 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8961 while(match = re.exec(html)){
8962 var attrs = match[1];
8963 var srcMatch = attrs ? attrs.match(srcRe) : false;
8964 if(srcMatch && srcMatch[2]){
8965 var s = document.createElement("script");
8966 s.src = srcMatch[2];
8967 var typeMatch = attrs.match(typeRe);
8968 if(typeMatch && typeMatch[2]){
8969 s.type = typeMatch[2];
8972 }else if(match[2] && match[2].length > 0){
8973 if(window.execScript) {
8974 window.execScript(match[2]);
8982 window.eval(match[2]);
8986 var el = document.getElementById(id);
8987 if(el){el.parentNode.removeChild(el);}
8988 if(typeof callback == "function"){
8992 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8997 * Direct access to the UpdateManager update() method (takes the same parameters).
8998 * @param {String/Function} url The url for this request or a function to call to get the url
8999 * @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}
9000 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9001 * @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.
9002 * @return {Roo.Element} this
9005 var um = this.getUpdateManager();
9006 um.update.apply(um, arguments);
9011 * Gets this element's UpdateManager
9012 * @return {Roo.UpdateManager} The UpdateManager
9014 getUpdateManager : function(){
9015 if(!this.updateManager){
9016 this.updateManager = new Roo.UpdateManager(this);
9018 return this.updateManager;
9022 * Disables text selection for this element (normalized across browsers)
9023 * @return {Roo.Element} this
9025 unselectable : function(){
9026 this.dom.unselectable = "on";
9027 this.swallowEvent("selectstart", true);
9028 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9029 this.addClass("x-unselectable");
9034 * Calculates the x, y to center this element on the screen
9035 * @return {Array} The x, y values [x, y]
9037 getCenterXY : function(){
9038 return this.getAlignToXY(document, 'c-c');
9042 * Centers the Element in either the viewport, or another Element.
9043 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9045 center : function(centerIn){
9046 this.alignTo(centerIn || document, 'c-c');
9051 * Tests various css rules/browsers to determine if this element uses a border box
9054 isBorderBox : function(){
9055 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9059 * Return a box {x, y, width, height} that can be used to set another elements
9060 * size/location to match this element.
9061 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9062 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9063 * @return {Object} box An object in the format {x, y, width, height}
9065 getBox : function(contentBox, local){
9070 var left = parseInt(this.getStyle("left"), 10) || 0;
9071 var top = parseInt(this.getStyle("top"), 10) || 0;
9074 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9076 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9078 var l = this.getBorderWidth("l")+this.getPadding("l");
9079 var r = this.getBorderWidth("r")+this.getPadding("r");
9080 var t = this.getBorderWidth("t")+this.getPadding("t");
9081 var b = this.getBorderWidth("b")+this.getPadding("b");
9082 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)};
9084 bx.right = bx.x + bx.width;
9085 bx.bottom = bx.y + bx.height;
9090 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9091 for more information about the sides.
9092 * @param {String} sides
9095 getFrameWidth : function(sides, onlyContentBox){
9096 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9100 * 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.
9101 * @param {Object} box The box to fill {x, y, width, height}
9102 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9103 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9104 * @return {Roo.Element} this
9106 setBox : function(box, adjust, animate){
9107 var w = box.width, h = box.height;
9108 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9109 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9110 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9112 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9117 * Forces the browser to repaint this element
9118 * @return {Roo.Element} this
9120 repaint : function(){
9122 this.addClass("x-repaint");
9123 setTimeout(function(){
9124 Roo.get(dom).removeClass("x-repaint");
9130 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9131 * then it returns the calculated width of the sides (see getPadding)
9132 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9133 * @return {Object/Number}
9135 getMargins : function(side){
9138 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9139 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9140 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9141 right: parseInt(this.getStyle("margin-right"), 10) || 0
9144 return this.addStyles(side, El.margins);
9149 addStyles : function(sides, styles){
9151 for(var i = 0, len = sides.length; i < len; i++){
9152 v = this.getStyle(styles[sides.charAt(i)]);
9154 w = parseInt(v, 10);
9162 * Creates a proxy element of this element
9163 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9164 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9165 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9166 * @return {Roo.Element} The new proxy element
9168 createProxy : function(config, renderTo, matchBox){
9170 renderTo = Roo.getDom(renderTo);
9172 renderTo = document.body;
9174 config = typeof config == "object" ?
9175 config : {tag : "div", cls: config};
9176 var proxy = Roo.DomHelper.append(renderTo, config, true);
9178 proxy.setBox(this.getBox());
9184 * Puts a mask over this element to disable user interaction. Requires core.css.
9185 * This method can only be applied to elements which accept child nodes.
9186 * @param {String} msg (optional) A message to display in the mask
9187 * @param {String} msgCls (optional) A css class to apply to the msg element
9188 * @return {Element} The mask element
9190 mask : function(msg, msgCls)
9192 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9193 this.setStyle("position", "relative");
9196 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9199 this.addClass("x-masked");
9200 this._mask.setDisplayed(true);
9205 while (dom && dom.style) {
9206 if (!isNaN(parseInt(dom.style.zIndex))) {
9207 z = Math.max(z, parseInt(dom.style.zIndex));
9209 dom = dom.parentNode;
9211 // if we are masking the body - then it hides everything..
9212 if (this.dom == document.body) {
9214 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9215 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9218 if(typeof msg == 'string'){
9220 this._maskMsg = Roo.DomHelper.append(this.dom, {
9221 cls: "roo-el-mask-msg",
9225 cls: 'fa fa-spinner fa-spin'
9233 var mm = this._maskMsg;
9234 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9235 if (mm.dom.lastChild) { // weird IE issue?
9236 mm.dom.lastChild.innerHTML = msg;
9238 mm.setDisplayed(true);
9240 mm.setStyle('z-index', z + 102);
9242 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9243 this._mask.setHeight(this.getHeight());
9245 this._mask.setStyle('z-index', z + 100);
9251 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9252 * it is cached for reuse.
9254 unmask : function(removeEl){
9256 if(removeEl === true){
9257 this._mask.remove();
9260 this._maskMsg.remove();
9261 delete this._maskMsg;
9264 this._mask.setDisplayed(false);
9266 this._maskMsg.setDisplayed(false);
9270 this.removeClass("x-masked");
9274 * Returns true if this element is masked
9277 isMasked : function(){
9278 return this._mask && this._mask.isVisible();
9282 * Creates an iframe shim for this element to keep selects and other windowed objects from
9284 * @return {Roo.Element} The new shim element
9286 createShim : function(){
9287 var el = document.createElement('iframe');
9288 el.frameBorder = 'no';
9289 el.className = 'roo-shim';
9290 if(Roo.isIE && Roo.isSecure){
9291 el.src = Roo.SSL_SECURE_URL;
9293 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9294 shim.autoBoxAdjust = false;
9299 * Removes this element from the DOM and deletes it from the cache
9301 remove : function(){
9302 if(this.dom.parentNode){
9303 this.dom.parentNode.removeChild(this.dom);
9305 delete El.cache[this.dom.id];
9309 * Sets up event handlers to add and remove a css class when the mouse is over this element
9310 * @param {String} className
9311 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9312 * mouseout events for children elements
9313 * @return {Roo.Element} this
9315 addClassOnOver : function(className, preventFlicker){
9316 this.on("mouseover", function(){
9317 Roo.fly(this, '_internal').addClass(className);
9319 var removeFn = function(e){
9320 if(preventFlicker !== true || !e.within(this, true)){
9321 Roo.fly(this, '_internal').removeClass(className);
9324 this.on("mouseout", removeFn, this.dom);
9329 * Sets up event handlers to add and remove a css class when this element has the focus
9330 * @param {String} className
9331 * @return {Roo.Element} this
9333 addClassOnFocus : function(className){
9334 this.on("focus", function(){
9335 Roo.fly(this, '_internal').addClass(className);
9337 this.on("blur", function(){
9338 Roo.fly(this, '_internal').removeClass(className);
9343 * 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)
9344 * @param {String} className
9345 * @return {Roo.Element} this
9347 addClassOnClick : function(className){
9349 this.on("mousedown", function(){
9350 Roo.fly(dom, '_internal').addClass(className);
9351 var d = Roo.get(document);
9352 var fn = function(){
9353 Roo.fly(dom, '_internal').removeClass(className);
9354 d.removeListener("mouseup", fn);
9356 d.on("mouseup", fn);
9362 * Stops the specified event from bubbling and optionally prevents the default action
9363 * @param {String} eventName
9364 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9365 * @return {Roo.Element} this
9367 swallowEvent : function(eventName, preventDefault){
9368 var fn = function(e){
9369 e.stopPropagation();
9374 if(eventName instanceof Array){
9375 for(var i = 0, len = eventName.length; i < len; i++){
9376 this.on(eventName[i], fn);
9380 this.on(eventName, fn);
9387 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9390 * Sizes this element to its parent element's dimensions performing
9391 * neccessary box adjustments.
9392 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9393 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9394 * @return {Roo.Element} this
9396 fitToParent : function(monitorResize, targetParent) {
9397 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9398 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9399 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9402 var p = Roo.get(targetParent || this.dom.parentNode);
9403 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9404 if (monitorResize === true) {
9405 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9406 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9412 * Gets the next sibling, skipping text nodes
9413 * @return {HTMLElement} The next sibling or null
9415 getNextSibling : function(){
9416 var n = this.dom.nextSibling;
9417 while(n && n.nodeType != 1){
9424 * Gets the previous sibling, skipping text nodes
9425 * @return {HTMLElement} The previous sibling or null
9427 getPrevSibling : function(){
9428 var n = this.dom.previousSibling;
9429 while(n && n.nodeType != 1){
9430 n = n.previousSibling;
9437 * Appends the passed element(s) to this element
9438 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9439 * @return {Roo.Element} this
9441 appendChild: function(el){
9448 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9449 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9450 * automatically generated with the specified attributes.
9451 * @param {HTMLElement} insertBefore (optional) a child element of this element
9452 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9453 * @return {Roo.Element} The new child element
9455 createChild: function(config, insertBefore, returnDom){
9456 config = config || {tag:'div'};
9458 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9460 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9464 * Appends this element to the passed element
9465 * @param {String/HTMLElement/Element} el The new parent element
9466 * @return {Roo.Element} this
9468 appendTo: function(el){
9469 el = Roo.getDom(el);
9470 el.appendChild(this.dom);
9475 * Inserts this element before the passed element in the DOM
9476 * @param {String/HTMLElement/Element} el The element to insert before
9477 * @return {Roo.Element} this
9479 insertBefore: function(el){
9480 el = Roo.getDom(el);
9481 el.parentNode.insertBefore(this.dom, el);
9486 * Inserts this element after the passed element in the DOM
9487 * @param {String/HTMLElement/Element} el The element to insert after
9488 * @return {Roo.Element} this
9490 insertAfter: function(el){
9491 el = Roo.getDom(el);
9492 el.parentNode.insertBefore(this.dom, el.nextSibling);
9497 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9498 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9499 * @return {Roo.Element} The new child
9501 insertFirst: function(el, returnDom){
9503 if(typeof el == 'object' && !el.nodeType){ // dh config
9504 return this.createChild(el, this.dom.firstChild, returnDom);
9506 el = Roo.getDom(el);
9507 this.dom.insertBefore(el, this.dom.firstChild);
9508 return !returnDom ? Roo.get(el) : el;
9513 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9514 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9515 * @param {String} where (optional) 'before' or 'after' defaults to before
9516 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9517 * @return {Roo.Element} the inserted Element
9519 insertSibling: function(el, where, returnDom){
9520 where = where ? where.toLowerCase() : 'before';
9522 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9524 if(typeof el == 'object' && !el.nodeType){ // dh config
9525 if(where == 'after' && !this.dom.nextSibling){
9526 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9528 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9532 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9533 where == 'before' ? this.dom : this.dom.nextSibling);
9542 * Creates and wraps this element with another element
9543 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9544 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9545 * @return {HTMLElement/Element} The newly created wrapper element
9547 wrap: function(config, returnDom){
9549 config = {tag: "div"};
9551 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9552 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9557 * Replaces the passed element with this element
9558 * @param {String/HTMLElement/Element} el The element to replace
9559 * @return {Roo.Element} this
9561 replace: function(el){
9563 this.insertBefore(el);
9569 * Inserts an html fragment into this element
9570 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9571 * @param {String} html The HTML fragment
9572 * @param {Boolean} returnEl True to return an Roo.Element
9573 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9575 insertHtml : function(where, html, returnEl){
9576 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9577 return returnEl ? Roo.get(el) : el;
9581 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9582 * @param {Object} o The object with the attributes
9583 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9584 * @return {Roo.Element} this
9586 set : function(o, useSet){
9588 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9590 if(attr == "style" || typeof o[attr] == "function") { continue; }
9592 el.className = o["cls"];
9595 el.setAttribute(attr, o[attr]);
9602 Roo.DomHelper.applyStyles(el, o.style);
9608 * Convenience method for constructing a KeyMap
9609 * @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:
9610 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9611 * @param {Function} fn The function to call
9612 * @param {Object} scope (optional) The scope of the function
9613 * @return {Roo.KeyMap} The KeyMap created
9615 addKeyListener : function(key, fn, scope){
9617 if(typeof key != "object" || key instanceof Array){
9633 return new Roo.KeyMap(this, config);
9637 * Creates a KeyMap for this element
9638 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9639 * @return {Roo.KeyMap} The KeyMap created
9641 addKeyMap : function(config){
9642 return new Roo.KeyMap(this, config);
9646 * Returns true if this element is scrollable.
9649 isScrollable : function(){
9651 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9655 * 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().
9656 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9657 * @param {Number} value The new scroll value
9658 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9659 * @return {Element} this
9662 scrollTo : function(side, value, animate){
9663 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9665 this.dom[prop] = value;
9667 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9668 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9674 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9675 * within this element's scrollable range.
9676 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9677 * @param {Number} distance How far to scroll the element in pixels
9678 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9679 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9680 * was scrolled as far as it could go.
9682 scroll : function(direction, distance, animate){
9683 if(!this.isScrollable()){
9687 var l = el.scrollLeft, t = el.scrollTop;
9688 var w = el.scrollWidth, h = el.scrollHeight;
9689 var cw = el.clientWidth, ch = el.clientHeight;
9690 direction = direction.toLowerCase();
9691 var scrolled = false;
9692 var a = this.preanim(arguments, 2);
9697 var v = Math.min(l + distance, w-cw);
9698 this.scrollTo("left", v, a);
9705 var v = Math.max(l - distance, 0);
9706 this.scrollTo("left", v, a);
9714 var v = Math.max(t - distance, 0);
9715 this.scrollTo("top", v, a);
9723 var v = Math.min(t + distance, h-ch);
9724 this.scrollTo("top", v, a);
9733 * Translates the passed page coordinates into left/top css values for this element
9734 * @param {Number/Array} x The page x or an array containing [x, y]
9735 * @param {Number} y The page y
9736 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9738 translatePoints : function(x, y){
9739 if(typeof x == 'object' || x instanceof Array){
9742 var p = this.getStyle('position');
9743 var o = this.getXY();
9745 var l = parseInt(this.getStyle('left'), 10);
9746 var t = parseInt(this.getStyle('top'), 10);
9749 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9752 t = (p == "relative") ? 0 : this.dom.offsetTop;
9755 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9759 * Returns the current scroll position of the element.
9760 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9762 getScroll : function(){
9763 var d = this.dom, doc = document;
9764 if(d == doc || d == doc.body){
9765 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9766 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9767 return {left: l, top: t};
9769 return {left: d.scrollLeft, top: d.scrollTop};
9774 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9775 * are convert to standard 6 digit hex color.
9776 * @param {String} attr The css attribute
9777 * @param {String} defaultValue The default value to use when a valid color isn't found
9778 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9781 getColor : function(attr, defaultValue, prefix){
9782 var v = this.getStyle(attr);
9783 if(!v || v == "transparent" || v == "inherit") {
9784 return defaultValue;
9786 var color = typeof prefix == "undefined" ? "#" : prefix;
9787 if(v.substr(0, 4) == "rgb("){
9788 var rvs = v.slice(4, v.length -1).split(",");
9789 for(var i = 0; i < 3; i++){
9790 var h = parseInt(rvs[i]).toString(16);
9797 if(v.substr(0, 1) == "#"){
9799 for(var i = 1; i < 4; i++){
9800 var c = v.charAt(i);
9803 }else if(v.length == 7){
9804 color += v.substr(1);
9808 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9812 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9813 * gradient background, rounded corners and a 4-way shadow.
9814 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9815 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9816 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9817 * @return {Roo.Element} this
9819 boxWrap : function(cls){
9820 cls = cls || 'x-box';
9821 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9822 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9827 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9828 * @param {String} namespace The namespace in which to look for the attribute
9829 * @param {String} name The attribute name
9830 * @return {String} The attribute value
9832 getAttributeNS : Roo.isIE ? function(ns, name){
9834 var type = typeof d[ns+":"+name];
9835 if(type != 'undefined' && type != 'unknown'){
9836 return d[ns+":"+name];
9839 } : function(ns, name){
9841 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9846 * Sets or Returns the value the dom attribute value
9847 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9848 * @param {String} value (optional) The value to set the attribute to
9849 * @return {String} The attribute value
9851 attr : function(name){
9852 if (arguments.length > 1) {
9853 this.dom.setAttribute(name, arguments[1]);
9854 return arguments[1];
9856 if (typeof(name) == 'object') {
9857 for(var i in name) {
9858 this.attr(i, name[i]);
9864 if (!this.dom.hasAttribute(name)) {
9867 return this.dom.getAttribute(name);
9874 var ep = El.prototype;
9877 * Appends an event handler (Shorthand for addListener)
9878 * @param {String} eventName The type of event to append
9879 * @param {Function} fn The method the event invokes
9880 * @param {Object} scope (optional) The scope (this object) of the fn
9881 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9884 ep.on = ep.addListener;
9886 ep.mon = ep.addListener;
9889 * Removes an event handler from this element (shorthand for removeListener)
9890 * @param {String} eventName the type of event to remove
9891 * @param {Function} fn the method the event invokes
9892 * @return {Roo.Element} this
9895 ep.un = ep.removeListener;
9898 * true to automatically adjust width and height settings for box-model issues (default to true)
9900 ep.autoBoxAdjust = true;
9903 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9906 El.addUnits = function(v, defaultUnit){
9907 if(v === "" || v == "auto"){
9910 if(v === undefined){
9913 if(typeof v == "number" || !El.unitPattern.test(v)){
9914 return v + (defaultUnit || 'px');
9919 // special markup used throughout Roo when box wrapping elements
9920 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>';
9922 * Visibility mode constant - Use visibility to hide element
9928 * Visibility mode constant - Use display to hide element
9934 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9935 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9936 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9948 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9949 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9950 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9951 * @return {Element} The Element object
9954 El.get = function(el){
9956 if(!el){ return null; }
9957 if(typeof el == "string"){ // element id
9958 if(!(elm = document.getElementById(el))){
9961 if(ex = El.cache[el]){
9964 ex = El.cache[el] = new El(elm);
9967 }else if(el.tagName){ // dom element
9971 if(ex = El.cache[id]){
9974 ex = El.cache[id] = new El(el);
9977 }else if(el instanceof El){
9979 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9980 // catch case where it hasn't been appended
9981 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9984 }else if(el.isComposite){
9986 }else if(el instanceof Array){
9987 return El.select(el);
9988 }else if(el == document){
9989 // create a bogus element object representing the document object
9991 var f = function(){};
9992 f.prototype = El.prototype;
9994 docEl.dom = document;
10002 El.uncache = function(el){
10003 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10005 delete El.cache[a[i].id || a[i]];
10011 // Garbage collection - uncache elements/purge listeners on orphaned elements
10012 // so we don't hold a reference and cause the browser to retain them
10013 El.garbageCollect = function(){
10014 if(!Roo.enableGarbageCollector){
10015 clearInterval(El.collectorThread);
10018 for(var eid in El.cache){
10019 var el = El.cache[eid], d = el.dom;
10020 // -------------------------------------------------------
10021 // Determining what is garbage:
10022 // -------------------------------------------------------
10024 // dom node is null, definitely garbage
10025 // -------------------------------------------------------
10027 // no parentNode == direct orphan, definitely garbage
10028 // -------------------------------------------------------
10029 // !d.offsetParent && !document.getElementById(eid)
10030 // display none elements have no offsetParent so we will
10031 // also try to look it up by it's id. However, check
10032 // offsetParent first so we don't do unneeded lookups.
10033 // This enables collection of elements that are not orphans
10034 // directly, but somewhere up the line they have an orphan
10036 // -------------------------------------------------------
10037 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10038 delete El.cache[eid];
10039 if(d && Roo.enableListenerCollection){
10045 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10049 El.Flyweight = function(dom){
10052 El.Flyweight.prototype = El.prototype;
10054 El._flyweights = {};
10056 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10057 * the dom node can be overwritten by other code.
10058 * @param {String/HTMLElement} el The dom node or id
10059 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10060 * prevent conflicts (e.g. internally Roo uses "_internal")
10062 * @return {Element} The shared Element object
10064 El.fly = function(el, named){
10065 named = named || '_global';
10066 el = Roo.getDom(el);
10070 if(!El._flyweights[named]){
10071 El._flyweights[named] = new El.Flyweight();
10073 El._flyweights[named].dom = el;
10074 return El._flyweights[named];
10078 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10079 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10080 * Shorthand of {@link Roo.Element#get}
10081 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10082 * @return {Element} The Element object
10088 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10089 * the dom node can be overwritten by other code.
10090 * Shorthand of {@link Roo.Element#fly}
10091 * @param {String/HTMLElement} el The dom node or id
10092 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10093 * prevent conflicts (e.g. internally Roo uses "_internal")
10095 * @return {Element} The shared Element object
10101 // speedy lookup for elements never to box adjust
10102 var noBoxAdjust = Roo.isStrict ? {
10105 input:1, select:1, textarea:1
10107 if(Roo.isIE || Roo.isGecko){
10108 noBoxAdjust['button'] = 1;
10112 Roo.EventManager.on(window, 'unload', function(){
10114 delete El._flyweights;
10122 Roo.Element.selectorFunction = Roo.DomQuery.select;
10125 Roo.Element.select = function(selector, unique, root){
10127 if(typeof selector == "string"){
10128 els = Roo.Element.selectorFunction(selector, root);
10129 }else if(selector.length !== undefined){
10132 throw "Invalid selector";
10134 if(unique === true){
10135 return new Roo.CompositeElement(els);
10137 return new Roo.CompositeElementLite(els);
10141 * Selects elements based on the passed CSS selector to enable working on them as 1.
10142 * @param {String/Array} selector The CSS selector or an array of elements
10143 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10144 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10145 * @return {CompositeElementLite/CompositeElement}
10149 Roo.select = Roo.Element.select;
10166 * Ext JS Library 1.1.1
10167 * Copyright(c) 2006-2007, Ext JS, LLC.
10169 * Originally Released Under LGPL - original licence link has changed is not relivant.
10172 * <script type="text/javascript">
10177 //Notifies Element that fx methods are available
10178 Roo.enableFx = true;
10182 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10183 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10184 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10185 * Element effects to work.</p><br/>
10187 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10188 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10189 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10190 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10191 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10192 * expected results and should be done with care.</p><br/>
10194 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10195 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10198 ----- -----------------------------
10199 tl The top left corner
10200 t The center of the top edge
10201 tr The top right corner
10202 l The center of the left edge
10203 r The center of the right edge
10204 bl The bottom left corner
10205 b The center of the bottom edge
10206 br The bottom right corner
10208 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10209 * below are common options that can be passed to any Fx method.</b>
10210 * @cfg {Function} callback A function called when the effect is finished
10211 * @cfg {Object} scope The scope of the effect function
10212 * @cfg {String} easing A valid Easing value for the effect
10213 * @cfg {String} afterCls A css class to apply after the effect
10214 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10215 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10216 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10217 * effects that end with the element being visually hidden, ignored otherwise)
10218 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10219 * a function which returns such a specification that will be applied to the Element after the effect finishes
10220 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10221 * @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
10222 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10226 * Slides the element into view. An anchor point can be optionally passed to set the point of
10227 * origin for the slide effect. This function automatically handles wrapping the element with
10228 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10231 // default: slide the element in from the top
10234 // custom: slide the element in from the right with a 2-second duration
10235 el.slideIn('r', { duration: 2 });
10237 // common config options shown with default values
10243 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10244 * @param {Object} options (optional) Object literal with any of the Fx config options
10245 * @return {Roo.Element} The Element
10247 slideIn : function(anchor, o){
10248 var el = this.getFxEl();
10251 el.queueFx(o, function(){
10253 anchor = anchor || "t";
10255 // fix display to visibility
10258 // restore values after effect
10259 var r = this.getFxRestore();
10260 var b = this.getBox();
10261 // fixed size for slide
10265 var wrap = this.fxWrap(r.pos, o, "hidden");
10267 var st = this.dom.style;
10268 st.visibility = "visible";
10269 st.position = "absolute";
10271 // clear out temp styles after slide and unwrap
10272 var after = function(){
10273 el.fxUnwrap(wrap, r.pos, o);
10274 st.width = r.width;
10275 st.height = r.height;
10278 // time to calc the positions
10279 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10281 switch(anchor.toLowerCase()){
10283 wrap.setSize(b.width, 0);
10284 st.left = st.bottom = "0";
10288 wrap.setSize(0, b.height);
10289 st.right = st.top = "0";
10293 wrap.setSize(0, b.height);
10294 wrap.setX(b.right);
10295 st.left = st.top = "0";
10296 a = {width: bw, points: pt};
10299 wrap.setSize(b.width, 0);
10300 wrap.setY(b.bottom);
10301 st.left = st.top = "0";
10302 a = {height: bh, points: pt};
10305 wrap.setSize(0, 0);
10306 st.right = st.bottom = "0";
10307 a = {width: bw, height: bh};
10310 wrap.setSize(0, 0);
10311 wrap.setY(b.y+b.height);
10312 st.right = st.top = "0";
10313 a = {width: bw, height: bh, points: pt};
10316 wrap.setSize(0, 0);
10317 wrap.setXY([b.right, b.bottom]);
10318 st.left = st.top = "0";
10319 a = {width: bw, height: bh, points: pt};
10322 wrap.setSize(0, 0);
10323 wrap.setX(b.x+b.width);
10324 st.left = st.bottom = "0";
10325 a = {width: bw, height: bh, points: pt};
10328 this.dom.style.visibility = "visible";
10331 arguments.callee.anim = wrap.fxanim(a,
10341 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10342 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10343 * 'hidden') but block elements will still take up space in the document. The element must be removed
10344 * from the DOM using the 'remove' config option if desired. This function automatically handles
10345 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10348 // default: slide the element out to the top
10351 // custom: slide the element out to the right with a 2-second duration
10352 el.slideOut('r', { duration: 2 });
10354 // common config options shown with default values
10362 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10363 * @param {Object} options (optional) Object literal with any of the Fx config options
10364 * @return {Roo.Element} The Element
10366 slideOut : function(anchor, o){
10367 var el = this.getFxEl();
10370 el.queueFx(o, function(){
10372 anchor = anchor || "t";
10374 // restore values after effect
10375 var r = this.getFxRestore();
10377 var b = this.getBox();
10378 // fixed size for slide
10382 var wrap = this.fxWrap(r.pos, o, "visible");
10384 var st = this.dom.style;
10385 st.visibility = "visible";
10386 st.position = "absolute";
10390 var after = function(){
10392 el.setDisplayed(false);
10397 el.fxUnwrap(wrap, r.pos, o);
10399 st.width = r.width;
10400 st.height = r.height;
10405 var a, zero = {to: 0};
10406 switch(anchor.toLowerCase()){
10408 st.left = st.bottom = "0";
10409 a = {height: zero};
10412 st.right = st.top = "0";
10416 st.left = st.top = "0";
10417 a = {width: zero, points: {to:[b.right, b.y]}};
10420 st.left = st.top = "0";
10421 a = {height: zero, points: {to:[b.x, b.bottom]}};
10424 st.right = st.bottom = "0";
10425 a = {width: zero, height: zero};
10428 st.right = st.top = "0";
10429 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10432 st.left = st.top = "0";
10433 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10436 st.left = st.bottom = "0";
10437 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10441 arguments.callee.anim = wrap.fxanim(a,
10451 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10452 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10453 * The element must be removed from the DOM using the 'remove' config option if desired.
10459 // common config options shown with default values
10467 * @param {Object} options (optional) Object literal with any of the Fx config options
10468 * @return {Roo.Element} The Element
10470 puff : function(o){
10471 var el = this.getFxEl();
10474 el.queueFx(o, function(){
10475 this.clearOpacity();
10478 // restore values after effect
10479 var r = this.getFxRestore();
10480 var st = this.dom.style;
10482 var after = function(){
10484 el.setDisplayed(false);
10491 el.setPositioning(r.pos);
10492 st.width = r.width;
10493 st.height = r.height;
10498 var width = this.getWidth();
10499 var height = this.getHeight();
10501 arguments.callee.anim = this.fxanim({
10502 width : {to: this.adjustWidth(width * 2)},
10503 height : {to: this.adjustHeight(height * 2)},
10504 points : {by: [-(width * .5), -(height * .5)]},
10506 fontSize: {to:200, unit: "%"}
10517 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10518 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10519 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10525 // all config options shown with default values
10533 * @param {Object} options (optional) Object literal with any of the Fx config options
10534 * @return {Roo.Element} The Element
10536 switchOff : function(o){
10537 var el = this.getFxEl();
10540 el.queueFx(o, function(){
10541 this.clearOpacity();
10544 // restore values after effect
10545 var r = this.getFxRestore();
10546 var st = this.dom.style;
10548 var after = function(){
10550 el.setDisplayed(false);
10556 el.setPositioning(r.pos);
10557 st.width = r.width;
10558 st.height = r.height;
10563 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10564 this.clearOpacity();
10568 points:{by:[0, this.getHeight() * .5]}
10569 }, o, 'motion', 0.3, 'easeIn', after);
10570 }).defer(100, this);
10577 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10578 * changed using the "attr" config option) and then fading back to the original color. If no original
10579 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10582 // default: highlight background to yellow
10585 // custom: highlight foreground text to blue for 2 seconds
10586 el.highlight("0000ff", { attr: 'color', duration: 2 });
10588 // common config options shown with default values
10589 el.highlight("ffff9c", {
10590 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10591 endColor: (current color) or "ffffff",
10596 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10597 * @param {Object} options (optional) Object literal with any of the Fx config options
10598 * @return {Roo.Element} The Element
10600 highlight : function(color, o){
10601 var el = this.getFxEl();
10604 el.queueFx(o, function(){
10605 color = color || "ffff9c";
10606 attr = o.attr || "backgroundColor";
10608 this.clearOpacity();
10611 var origColor = this.getColor(attr);
10612 var restoreColor = this.dom.style[attr];
10613 endColor = (o.endColor || origColor) || "ffffff";
10615 var after = function(){
10616 el.dom.style[attr] = restoreColor;
10621 a[attr] = {from: color, to: endColor};
10622 arguments.callee.anim = this.fxanim(a,
10632 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10635 // default: a single light blue ripple
10638 // custom: 3 red ripples lasting 3 seconds total
10639 el.frame("ff0000", 3, { duration: 3 });
10641 // common config options shown with default values
10642 el.frame("C3DAF9", 1, {
10643 duration: 1 //duration of entire animation (not each individual ripple)
10644 // Note: Easing is not configurable and will be ignored if included
10647 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10648 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10649 * @param {Object} options (optional) Object literal with any of the Fx config options
10650 * @return {Roo.Element} The Element
10652 frame : function(color, count, o){
10653 var el = this.getFxEl();
10656 el.queueFx(o, function(){
10657 color = color || "#C3DAF9";
10658 if(color.length == 6){
10659 color = "#" + color;
10661 count = count || 1;
10662 duration = o.duration || 1;
10665 var b = this.getBox();
10666 var animFn = function(){
10667 var proxy = this.createProxy({
10670 visbility:"hidden",
10671 position:"absolute",
10672 "z-index":"35000", // yee haw
10673 border:"0px solid " + color
10676 var scale = Roo.isBorderBox ? 2 : 1;
10678 top:{from:b.y, to:b.y - 20},
10679 left:{from:b.x, to:b.x - 20},
10680 borderWidth:{from:0, to:10},
10681 opacity:{from:1, to:0},
10682 height:{from:b.height, to:(b.height + (20*scale))},
10683 width:{from:b.width, to:(b.width + (20*scale))}
10684 }, duration, function(){
10688 animFn.defer((duration/2)*1000, this);
10699 * Creates a pause before any subsequent queued effects begin. If there are
10700 * no effects queued after the pause it will have no effect.
10705 * @param {Number} seconds The length of time to pause (in seconds)
10706 * @return {Roo.Element} The Element
10708 pause : function(seconds){
10709 var el = this.getFxEl();
10712 el.queueFx(o, function(){
10713 setTimeout(function(){
10715 }, seconds * 1000);
10721 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10722 * using the "endOpacity" config option.
10725 // default: fade in from opacity 0 to 100%
10728 // custom: fade in from opacity 0 to 75% over 2 seconds
10729 el.fadeIn({ endOpacity: .75, duration: 2});
10731 // common config options shown with default values
10733 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10738 * @param {Object} options (optional) Object literal with any of the Fx config options
10739 * @return {Roo.Element} The Element
10741 fadeIn : function(o){
10742 var el = this.getFxEl();
10744 el.queueFx(o, function(){
10745 this.setOpacity(0);
10747 this.dom.style.visibility = 'visible';
10748 var to = o.endOpacity || 1;
10749 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10750 o, null, .5, "easeOut", function(){
10752 this.clearOpacity();
10761 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10762 * using the "endOpacity" config option.
10765 // default: fade out from the element's current opacity to 0
10768 // custom: fade out from the element's current opacity to 25% over 2 seconds
10769 el.fadeOut({ endOpacity: .25, duration: 2});
10771 // common config options shown with default values
10773 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10780 * @param {Object} options (optional) Object literal with any of the Fx config options
10781 * @return {Roo.Element} The Element
10783 fadeOut : function(o){
10784 var el = this.getFxEl();
10786 el.queueFx(o, function(){
10787 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10788 o, null, .5, "easeOut", function(){
10789 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10790 this.dom.style.display = "none";
10792 this.dom.style.visibility = "hidden";
10794 this.clearOpacity();
10802 * Animates the transition of an element's dimensions from a starting height/width
10803 * to an ending height/width.
10806 // change height and width to 100x100 pixels
10807 el.scale(100, 100);
10809 // common config options shown with default values. The height and width will default to
10810 // the element's existing values if passed as null.
10813 [element's height], {
10818 * @param {Number} width The new width (pass undefined to keep the original width)
10819 * @param {Number} height The new height (pass undefined to keep the original height)
10820 * @param {Object} options (optional) Object literal with any of the Fx config options
10821 * @return {Roo.Element} The Element
10823 scale : function(w, h, o){
10824 this.shift(Roo.apply({}, o, {
10832 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10833 * Any of these properties not specified in the config object will not be changed. This effect
10834 * requires that at least one new dimension, position or opacity setting must be passed in on
10835 * the config object in order for the function to have any effect.
10838 // slide the element horizontally to x position 200 while changing the height and opacity
10839 el.shift({ x: 200, height: 50, opacity: .8 });
10841 // common config options shown with default values.
10843 width: [element's width],
10844 height: [element's height],
10845 x: [element's x position],
10846 y: [element's y position],
10847 opacity: [element's opacity],
10852 * @param {Object} options Object literal with any of the Fx config options
10853 * @return {Roo.Element} The Element
10855 shift : function(o){
10856 var el = this.getFxEl();
10858 el.queueFx(o, function(){
10859 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10860 if(w !== undefined){
10861 a.width = {to: this.adjustWidth(w)};
10863 if(h !== undefined){
10864 a.height = {to: this.adjustHeight(h)};
10866 if(x !== undefined || y !== undefined){
10868 x !== undefined ? x : this.getX(),
10869 y !== undefined ? y : this.getY()
10872 if(op !== undefined){
10873 a.opacity = {to: op};
10875 if(o.xy !== undefined){
10876 a.points = {to: o.xy};
10878 arguments.callee.anim = this.fxanim(a,
10879 o, 'motion', .35, "easeOut", function(){
10887 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10888 * ending point of the effect.
10891 // default: slide the element downward while fading out
10894 // custom: slide the element out to the right with a 2-second duration
10895 el.ghost('r', { duration: 2 });
10897 // common config options shown with default values
10905 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10906 * @param {Object} options (optional) Object literal with any of the Fx config options
10907 * @return {Roo.Element} The Element
10909 ghost : function(anchor, o){
10910 var el = this.getFxEl();
10913 el.queueFx(o, function(){
10914 anchor = anchor || "b";
10916 // restore values after effect
10917 var r = this.getFxRestore();
10918 var w = this.getWidth(),
10919 h = this.getHeight();
10921 var st = this.dom.style;
10923 var after = function(){
10925 el.setDisplayed(false);
10931 el.setPositioning(r.pos);
10932 st.width = r.width;
10933 st.height = r.height;
10938 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10939 switch(anchor.toLowerCase()){
10966 arguments.callee.anim = this.fxanim(a,
10976 * Ensures that all effects queued after syncFx is called on the element are
10977 * run concurrently. This is the opposite of {@link #sequenceFx}.
10978 * @return {Roo.Element} The Element
10980 syncFx : function(){
10981 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10990 * Ensures that all effects queued after sequenceFx is called on the element are
10991 * run in sequence. This is the opposite of {@link #syncFx}.
10992 * @return {Roo.Element} The Element
10994 sequenceFx : function(){
10995 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10997 concurrent : false,
11004 nextFx : function(){
11005 var ef = this.fxQueue[0];
11012 * Returns true if the element has any effects actively running or queued, else returns false.
11013 * @return {Boolean} True if element has active effects, else false
11015 hasActiveFx : function(){
11016 return this.fxQueue && this.fxQueue[0];
11020 * Stops any running effects and clears the element's internal effects queue if it contains
11021 * any additional effects that haven't started yet.
11022 * @return {Roo.Element} The Element
11024 stopFx : function(){
11025 if(this.hasActiveFx()){
11026 var cur = this.fxQueue[0];
11027 if(cur && cur.anim && cur.anim.isAnimated()){
11028 this.fxQueue = [cur]; // clear out others
11029 cur.anim.stop(true);
11036 beforeFx : function(o){
11037 if(this.hasActiveFx() && !o.concurrent){
11048 * Returns true if the element is currently blocking so that no other effect can be queued
11049 * until this effect is finished, else returns false if blocking is not set. This is commonly
11050 * used to ensure that an effect initiated by a user action runs to completion prior to the
11051 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11052 * @return {Boolean} True if blocking, else false
11054 hasFxBlock : function(){
11055 var q = this.fxQueue;
11056 return q && q[0] && q[0].block;
11060 queueFx : function(o, fn){
11064 if(!this.hasFxBlock()){
11065 Roo.applyIf(o, this.fxDefaults);
11067 var run = this.beforeFx(o);
11068 fn.block = o.block;
11069 this.fxQueue.push(fn);
11081 fxWrap : function(pos, o, vis){
11083 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11086 wrapXY = this.getXY();
11088 var div = document.createElement("div");
11089 div.style.visibility = vis;
11090 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11091 wrap.setPositioning(pos);
11092 if(wrap.getStyle("position") == "static"){
11093 wrap.position("relative");
11095 this.clearPositioning('auto');
11097 wrap.dom.appendChild(this.dom);
11099 wrap.setXY(wrapXY);
11106 fxUnwrap : function(wrap, pos, o){
11107 this.clearPositioning();
11108 this.setPositioning(pos);
11110 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11116 getFxRestore : function(){
11117 var st = this.dom.style;
11118 return {pos: this.getPositioning(), width: st.width, height : st.height};
11122 afterFx : function(o){
11124 this.applyStyles(o.afterStyle);
11127 this.addClass(o.afterCls);
11129 if(o.remove === true){
11132 Roo.callback(o.callback, o.scope, [this]);
11134 this.fxQueue.shift();
11140 getFxEl : function(){ // support for composite element fx
11141 return Roo.get(this.dom);
11145 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11146 animType = animType || 'run';
11148 var anim = Roo.lib.Anim[animType](
11150 (opt.duration || defaultDur) || .35,
11151 (opt.easing || defaultEase) || 'easeOut',
11153 Roo.callback(cb, this);
11162 // backwords compat
11163 Roo.Fx.resize = Roo.Fx.scale;
11165 //When included, Roo.Fx is automatically applied to Element so that all basic
11166 //effects are available directly via the Element API
11167 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11169 * Ext JS Library 1.1.1
11170 * Copyright(c) 2006-2007, Ext JS, LLC.
11172 * Originally Released Under LGPL - original licence link has changed is not relivant.
11175 * <script type="text/javascript">
11180 * @class Roo.CompositeElement
11181 * Standard composite class. Creates a Roo.Element for every element in the collection.
11183 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11184 * actions will be performed on all the elements in this collection.</b>
11186 * All methods return <i>this</i> and can be chained.
11188 var els = Roo.select("#some-el div.some-class", true);
11189 // or select directly from an existing element
11190 var el = Roo.get('some-el');
11191 el.select('div.some-class', true);
11193 els.setWidth(100); // all elements become 100 width
11194 els.hide(true); // all elements fade out and hide
11196 els.setWidth(100).hide(true);
11199 Roo.CompositeElement = function(els){
11200 this.elements = [];
11201 this.addElements(els);
11203 Roo.CompositeElement.prototype = {
11205 addElements : function(els){
11209 if(typeof els == "string"){
11210 els = Roo.Element.selectorFunction(els);
11212 var yels = this.elements;
11213 var index = yels.length-1;
11214 for(var i = 0, len = els.length; i < len; i++) {
11215 yels[++index] = Roo.get(els[i]);
11221 * Clears this composite and adds the elements returned by the passed selector.
11222 * @param {String/Array} els A string CSS selector, an array of elements or an element
11223 * @return {CompositeElement} this
11225 fill : function(els){
11226 this.elements = [];
11232 * Filters this composite to only elements that match the passed selector.
11233 * @param {String} selector A string CSS selector
11234 * @param {Boolean} inverse return inverse filter (not matches)
11235 * @return {CompositeElement} this
11237 filter : function(selector, inverse){
11239 inverse = inverse || false;
11240 this.each(function(el){
11241 var match = inverse ? !el.is(selector) : el.is(selector);
11243 els[els.length] = el.dom;
11250 invoke : function(fn, args){
11251 var els = this.elements;
11252 for(var i = 0, len = els.length; i < len; i++) {
11253 Roo.Element.prototype[fn].apply(els[i], args);
11258 * Adds elements to this composite.
11259 * @param {String/Array} els A string CSS selector, an array of elements or an element
11260 * @return {CompositeElement} this
11262 add : function(els){
11263 if(typeof els == "string"){
11264 this.addElements(Roo.Element.selectorFunction(els));
11265 }else if(els.length !== undefined){
11266 this.addElements(els);
11268 this.addElements([els]);
11273 * Calls the passed function passing (el, this, index) for each element in this composite.
11274 * @param {Function} fn The function to call
11275 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11276 * @return {CompositeElement} this
11278 each : function(fn, scope){
11279 var els = this.elements;
11280 for(var i = 0, len = els.length; i < len; i++){
11281 if(fn.call(scope || els[i], els[i], this, i) === false) {
11289 * Returns the Element object at the specified index
11290 * @param {Number} index
11291 * @return {Roo.Element}
11293 item : function(index){
11294 return this.elements[index] || null;
11298 * Returns the first Element
11299 * @return {Roo.Element}
11301 first : function(){
11302 return this.item(0);
11306 * Returns the last Element
11307 * @return {Roo.Element}
11310 return this.item(this.elements.length-1);
11314 * Returns the number of elements in this composite
11317 getCount : function(){
11318 return this.elements.length;
11322 * Returns true if this composite contains the passed element
11325 contains : function(el){
11326 return this.indexOf(el) !== -1;
11330 * Returns true if this composite contains the passed element
11333 indexOf : function(el){
11334 return this.elements.indexOf(Roo.get(el));
11339 * Removes the specified element(s).
11340 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11341 * or an array of any of those.
11342 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11343 * @return {CompositeElement} this
11345 removeElement : function(el, removeDom){
11346 if(el instanceof Array){
11347 for(var i = 0, len = el.length; i < len; i++){
11348 this.removeElement(el[i]);
11352 var index = typeof el == 'number' ? el : this.indexOf(el);
11355 var d = this.elements[index];
11359 d.parentNode.removeChild(d);
11362 this.elements.splice(index, 1);
11368 * Replaces the specified element with the passed element.
11369 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11371 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11372 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11373 * @return {CompositeElement} this
11375 replaceElement : function(el, replacement, domReplace){
11376 var index = typeof el == 'number' ? el : this.indexOf(el);
11379 this.elements[index].replaceWith(replacement);
11381 this.elements.splice(index, 1, Roo.get(replacement))
11388 * Removes all elements.
11390 clear : function(){
11391 this.elements = [];
11395 Roo.CompositeElement.createCall = function(proto, fnName){
11396 if(!proto[fnName]){
11397 proto[fnName] = function(){
11398 return this.invoke(fnName, arguments);
11402 for(var fnName in Roo.Element.prototype){
11403 if(typeof Roo.Element.prototype[fnName] == "function"){
11404 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11410 * Ext JS Library 1.1.1
11411 * Copyright(c) 2006-2007, Ext JS, LLC.
11413 * Originally Released Under LGPL - original licence link has changed is not relivant.
11416 * <script type="text/javascript">
11420 * @class Roo.CompositeElementLite
11421 * @extends Roo.CompositeElement
11422 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11424 var els = Roo.select("#some-el div.some-class");
11425 // or select directly from an existing element
11426 var el = Roo.get('some-el');
11427 el.select('div.some-class');
11429 els.setWidth(100); // all elements become 100 width
11430 els.hide(true); // all elements fade out and hide
11432 els.setWidth(100).hide(true);
11433 </code></pre><br><br>
11434 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11435 * actions will be performed on all the elements in this collection.</b>
11437 Roo.CompositeElementLite = function(els){
11438 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11439 this.el = new Roo.Element.Flyweight();
11441 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11442 addElements : function(els){
11444 if(els instanceof Array){
11445 this.elements = this.elements.concat(els);
11447 var yels = this.elements;
11448 var index = yels.length-1;
11449 for(var i = 0, len = els.length; i < len; i++) {
11450 yels[++index] = els[i];
11456 invoke : function(fn, args){
11457 var els = this.elements;
11459 for(var i = 0, len = els.length; i < len; i++) {
11461 Roo.Element.prototype[fn].apply(el, args);
11466 * Returns a flyweight Element of the dom element object at the specified index
11467 * @param {Number} index
11468 * @return {Roo.Element}
11470 item : function(index){
11471 if(!this.elements[index]){
11474 this.el.dom = this.elements[index];
11478 // fixes scope with flyweight
11479 addListener : function(eventName, handler, scope, opt){
11480 var els = this.elements;
11481 for(var i = 0, len = els.length; i < len; i++) {
11482 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11488 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11489 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11490 * a reference to the dom node, use el.dom.</b>
11491 * @param {Function} fn The function to call
11492 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11493 * @return {CompositeElement} this
11495 each : function(fn, scope){
11496 var els = this.elements;
11498 for(var i = 0, len = els.length; i < len; i++){
11500 if(fn.call(scope || el, el, this, i) === false){
11507 indexOf : function(el){
11508 return this.elements.indexOf(Roo.getDom(el));
11511 replaceElement : function(el, replacement, domReplace){
11512 var index = typeof el == 'number' ? el : this.indexOf(el);
11514 replacement = Roo.getDom(replacement);
11516 var d = this.elements[index];
11517 d.parentNode.insertBefore(replacement, d);
11518 d.parentNode.removeChild(d);
11520 this.elements.splice(index, 1, replacement);
11525 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11529 * Ext JS Library 1.1.1
11530 * Copyright(c) 2006-2007, Ext JS, LLC.
11532 * Originally Released Under LGPL - original licence link has changed is not relivant.
11535 * <script type="text/javascript">
11541 * @class Roo.data.Connection
11542 * @extends Roo.util.Observable
11543 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11544 * either to a configured URL, or to a URL specified at request time.
11546 * Requests made by this class are asynchronous, and will return immediately. No data from
11547 * the server will be available to the statement immediately following the {@link #request} call.
11548 * To process returned data, use a callback in the request options object, or an event listener.
11550 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11551 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11552 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11553 * property and, if present, the IFRAME's XML document as the responseXML property.
11555 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11556 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11557 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11558 * standard DOM methods.
11560 * @param {Object} config a configuration object.
11562 Roo.data.Connection = function(config){
11563 Roo.apply(this, config);
11566 * @event beforerequest
11567 * Fires before a network request is made to retrieve a data object.
11568 * @param {Connection} conn This Connection object.
11569 * @param {Object} options The options config object passed to the {@link #request} method.
11571 "beforerequest" : true,
11573 * @event requestcomplete
11574 * Fires if the request was successfully completed.
11575 * @param {Connection} conn This Connection object.
11576 * @param {Object} response The XHR object containing the response data.
11577 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11578 * @param {Object} options The options config object passed to the {@link #request} method.
11580 "requestcomplete" : true,
11582 * @event requestexception
11583 * Fires if an error HTTP status was returned from the server.
11584 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11585 * @param {Connection} conn This Connection object.
11586 * @param {Object} response The XHR object containing the response data.
11587 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11588 * @param {Object} options The options config object passed to the {@link #request} method.
11590 "requestexception" : true
11592 Roo.data.Connection.superclass.constructor.call(this);
11595 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11597 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11600 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11601 * extra parameters to each request made by this object. (defaults to undefined)
11604 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11605 * to each request made by this object. (defaults to undefined)
11608 * @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)
11611 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11615 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11621 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11624 disableCaching: true,
11627 * Sends an HTTP request to a remote server.
11628 * @param {Object} options An object which may contain the following properties:<ul>
11629 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11630 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11631 * request, a url encoded string or a function to call to get either.</li>
11632 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11633 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11634 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11635 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11636 * <li>options {Object} The parameter to the request call.</li>
11637 * <li>success {Boolean} True if the request succeeded.</li>
11638 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11640 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11641 * The callback is passed the following parameters:<ul>
11642 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11643 * <li>options {Object} The parameter to the request call.</li>
11645 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11646 * The callback is passed the following parameters:<ul>
11647 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11648 * <li>options {Object} The parameter to the request call.</li>
11650 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11651 * for the callback function. Defaults to the browser window.</li>
11652 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11653 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11654 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11655 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11656 * params for the post data. Any params will be appended to the URL.</li>
11657 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11659 * @return {Number} transactionId
11661 request : function(o){
11662 if(this.fireEvent("beforerequest", this, o) !== false){
11665 if(typeof p == "function"){
11666 p = p.call(o.scope||window, o);
11668 if(typeof p == "object"){
11669 p = Roo.urlEncode(o.params);
11671 if(this.extraParams){
11672 var extras = Roo.urlEncode(this.extraParams);
11673 p = p ? (p + '&' + extras) : extras;
11676 var url = o.url || this.url;
11677 if(typeof url == 'function'){
11678 url = url.call(o.scope||window, o);
11682 var form = Roo.getDom(o.form);
11683 url = url || form.action;
11685 var enctype = form.getAttribute("enctype");
11688 return this.doFormDataUpload(o, url);
11691 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11692 return this.doFormUpload(o, p, url);
11694 var f = Roo.lib.Ajax.serializeForm(form);
11695 p = p ? (p + '&' + f) : f;
11698 if (!o.form && o.formData) {
11699 o.formData = o.formData === true ? new FormData() : o.formData;
11700 for (var k in o.params) {
11701 o.formData.append(k,o.params[k]);
11704 return this.doFormDataUpload(o, url);
11708 var hs = o.headers;
11709 if(this.defaultHeaders){
11710 hs = Roo.apply(hs || {}, this.defaultHeaders);
11717 success: this.handleResponse,
11718 failure: this.handleFailure,
11720 argument: {options: o},
11721 timeout : o.timeout || this.timeout
11724 var method = o.method||this.method||(p ? "POST" : "GET");
11726 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11727 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11730 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11734 }else if(this.autoAbort !== false){
11738 if((method == 'GET' && p) || o.xmlData){
11739 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11742 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11743 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11744 Roo.lib.Ajax.useDefaultHeader == true;
11745 return this.transId;
11747 Roo.callback(o.callback, o.scope, [o, null, null]);
11753 * Determine whether this object has a request outstanding.
11754 * @param {Number} transactionId (Optional) defaults to the last transaction
11755 * @return {Boolean} True if there is an outstanding request.
11757 isLoading : function(transId){
11759 return Roo.lib.Ajax.isCallInProgress(transId);
11761 return this.transId ? true : false;
11766 * Aborts any outstanding request.
11767 * @param {Number} transactionId (Optional) defaults to the last transaction
11769 abort : function(transId){
11770 if(transId || this.isLoading()){
11771 Roo.lib.Ajax.abort(transId || this.transId);
11776 handleResponse : function(response){
11777 this.transId = false;
11778 var options = response.argument.options;
11779 response.argument = options ? options.argument : null;
11780 this.fireEvent("requestcomplete", this, response, options);
11781 Roo.callback(options.success, options.scope, [response, options]);
11782 Roo.callback(options.callback, options.scope, [options, true, response]);
11786 handleFailure : function(response, e){
11787 this.transId = false;
11788 var options = response.argument.options;
11789 response.argument = options ? options.argument : null;
11790 this.fireEvent("requestexception", this, response, options, e);
11791 Roo.callback(options.failure, options.scope, [response, options]);
11792 Roo.callback(options.callback, options.scope, [options, false, response]);
11796 doFormUpload : function(o, ps, url){
11798 var frame = document.createElement('iframe');
11801 frame.className = 'x-hidden';
11803 frame.src = Roo.SSL_SECURE_URL;
11805 document.body.appendChild(frame);
11808 document.frames[id].name = id;
11811 var form = Roo.getDom(o.form);
11813 form.method = 'POST';
11814 form.enctype = form.encoding = 'multipart/form-data';
11820 if(ps){ // add dynamic params
11822 ps = Roo.urlDecode(ps, false);
11824 if(ps.hasOwnProperty(k)){
11825 hd = document.createElement('input');
11826 hd.type = 'hidden';
11829 form.appendChild(hd);
11836 var r = { // bogus response object
11841 r.argument = o ? o.argument : null;
11846 doc = frame.contentWindow.document;
11848 doc = (frame.contentDocument || window.frames[id].document);
11850 if(doc && doc.body){
11851 r.responseText = doc.body.innerHTML;
11853 if(doc && doc.XMLDocument){
11854 r.responseXML = doc.XMLDocument;
11856 r.responseXML = doc;
11863 Roo.EventManager.removeListener(frame, 'load', cb, this);
11865 this.fireEvent("requestcomplete", this, r, o);
11866 Roo.callback(o.success, o.scope, [r, o]);
11867 Roo.callback(o.callback, o.scope, [o, true, r]);
11869 setTimeout(function(){document.body.removeChild(frame);}, 100);
11872 Roo.EventManager.on(frame, 'load', cb, this);
11875 if(hiddens){ // remove dynamic params
11876 for(var i = 0, len = hiddens.length; i < len; i++){
11877 form.removeChild(hiddens[i]);
11881 // this is a 'formdata version???'
11884 doFormDataUpload : function(o, url)
11888 var form = Roo.getDom(o.form);
11889 form.enctype = form.encoding = 'multipart/form-data';
11890 formData = o.formData === true ? new FormData(form) : o.formData;
11892 formData = o.formData === true ? new FormData() : o.formData;
11897 success: this.handleResponse,
11898 failure: this.handleFailure,
11900 argument: {options: o},
11901 timeout : o.timeout || this.timeout
11904 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11908 }else if(this.autoAbort !== false){
11912 //Roo.lib.Ajax.defaultPostHeader = null;
11913 Roo.lib.Ajax.useDefaultHeader = false;
11914 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11915 Roo.lib.Ajax.useDefaultHeader = true;
11923 * Ext JS Library 1.1.1
11924 * Copyright(c) 2006-2007, Ext JS, LLC.
11926 * Originally Released Under LGPL - original licence link has changed is not relivant.
11929 * <script type="text/javascript">
11933 * Global Ajax request class.
11936 * @extends Roo.data.Connection
11939 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11940 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11941 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11942 * @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)
11943 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11944 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11945 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11947 Roo.Ajax = new Roo.data.Connection({
11956 * Serialize the passed form into a url encoded string
11958 * @param {String/HTMLElement} form
11961 serializeForm : function(form){
11962 return Roo.lib.Ajax.serializeForm(form);
11966 * Ext JS Library 1.1.1
11967 * Copyright(c) 2006-2007, Ext JS, LLC.
11969 * Originally Released Under LGPL - original licence link has changed is not relivant.
11972 * <script type="text/javascript">
11977 * @class Roo.UpdateManager
11978 * @extends Roo.util.Observable
11979 * Provides AJAX-style update for Element object.<br><br>
11982 * // Get it from a Roo.Element object
11983 * var el = Roo.get("foo");
11984 * var mgr = el.getUpdateManager();
11985 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11987 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11989 * // or directly (returns the same UpdateManager instance)
11990 * var mgr = new Roo.UpdateManager("myElementId");
11991 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11992 * mgr.on("update", myFcnNeedsToKnow);
11994 // short handed call directly from the element object
11995 Roo.get("foo").load({
11999 text: "Loading Foo..."
12003 * Create new UpdateManager directly.
12004 * @param {String/HTMLElement/Roo.Element} el The element to update
12005 * @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).
12007 Roo.UpdateManager = function(el, forceNew){
12009 if(!forceNew && el.updateManager){
12010 return el.updateManager;
12013 * The Element object
12014 * @type Roo.Element
12018 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12021 this.defaultUrl = null;
12025 * @event beforeupdate
12026 * Fired before an update is made, return false from your handler and the update is cancelled.
12027 * @param {Roo.Element} el
12028 * @param {String/Object/Function} url
12029 * @param {String/Object} params
12031 "beforeupdate": true,
12034 * Fired after successful update is made.
12035 * @param {Roo.Element} el
12036 * @param {Object} oResponseObject The response Object
12041 * Fired on update failure.
12042 * @param {Roo.Element} el
12043 * @param {Object} oResponseObject The response Object
12047 var d = Roo.UpdateManager.defaults;
12049 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12052 this.sslBlankUrl = d.sslBlankUrl;
12054 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12057 this.disableCaching = d.disableCaching;
12059 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12062 this.indicatorText = d.indicatorText;
12064 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12067 this.showLoadIndicator = d.showLoadIndicator;
12069 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12072 this.timeout = d.timeout;
12075 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12078 this.loadScripts = d.loadScripts;
12081 * Transaction object of current executing transaction
12083 this.transaction = null;
12088 this.autoRefreshProcId = null;
12090 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12093 this.refreshDelegate = this.refresh.createDelegate(this);
12095 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12098 this.updateDelegate = this.update.createDelegate(this);
12100 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12103 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12107 this.successDelegate = this.processSuccess.createDelegate(this);
12111 this.failureDelegate = this.processFailure.createDelegate(this);
12113 if(!this.renderer){
12115 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12117 this.renderer = new Roo.UpdateManager.BasicRenderer();
12120 Roo.UpdateManager.superclass.constructor.call(this);
12123 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12125 * Get the Element this UpdateManager is bound to
12126 * @return {Roo.Element} The element
12128 getEl : function(){
12132 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12133 * @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:
12136 url: "your-url.php",<br/>
12137 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12138 callback: yourFunction,<br/>
12139 scope: yourObject, //(optional scope) <br/>
12140 discardUrl: false, <br/>
12141 nocache: false,<br/>
12142 text: "Loading...",<br/>
12144 scripts: false<br/>
12147 * The only required property is url. The optional properties nocache, text and scripts
12148 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12149 * @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}
12150 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12151 * @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.
12153 update : function(url, params, callback, discardUrl){
12154 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12155 var method = this.method,
12157 if(typeof url == "object"){ // must be config object
12160 params = params || cfg.params;
12161 callback = callback || cfg.callback;
12162 discardUrl = discardUrl || cfg.discardUrl;
12163 if(callback && cfg.scope){
12164 callback = callback.createDelegate(cfg.scope);
12166 if(typeof cfg.method != "undefined"){method = cfg.method;};
12167 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12168 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12169 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12170 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12172 this.showLoading();
12174 this.defaultUrl = url;
12176 if(typeof url == "function"){
12177 url = url.call(this);
12180 method = method || (params ? "POST" : "GET");
12181 if(method == "GET"){
12182 url = this.prepareUrl(url);
12185 var o = Roo.apply(cfg ||{}, {
12188 success: this.successDelegate,
12189 failure: this.failureDelegate,
12190 callback: undefined,
12191 timeout: (this.timeout*1000),
12192 argument: {"url": url, "form": null, "callback": callback, "params": params}
12194 Roo.log("updated manager called with timeout of " + o.timeout);
12195 this.transaction = Roo.Ajax.request(o);
12200 * 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.
12201 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12202 * @param {String/HTMLElement} form The form Id or form element
12203 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12204 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12205 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12207 formUpdate : function(form, url, reset, callback){
12208 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12209 if(typeof url == "function"){
12210 url = url.call(this);
12212 form = Roo.getDom(form);
12213 this.transaction = Roo.Ajax.request({
12216 success: this.successDelegate,
12217 failure: this.failureDelegate,
12218 timeout: (this.timeout*1000),
12219 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12221 this.showLoading.defer(1, this);
12226 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12227 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12229 refresh : function(callback){
12230 if(this.defaultUrl == null){
12233 this.update(this.defaultUrl, null, callback, true);
12237 * Set this element to auto refresh.
12238 * @param {Number} interval How often to update (in seconds).
12239 * @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)
12240 * @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}
12241 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12242 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12244 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12246 this.update(url || this.defaultUrl, params, callback, true);
12248 if(this.autoRefreshProcId){
12249 clearInterval(this.autoRefreshProcId);
12251 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12255 * Stop auto refresh on this element.
12257 stopAutoRefresh : function(){
12258 if(this.autoRefreshProcId){
12259 clearInterval(this.autoRefreshProcId);
12260 delete this.autoRefreshProcId;
12264 isAutoRefreshing : function(){
12265 return this.autoRefreshProcId ? true : false;
12268 * Called to update the element to "Loading" state. Override to perform custom action.
12270 showLoading : function(){
12271 if(this.showLoadIndicator){
12272 this.el.update(this.indicatorText);
12277 * Adds unique parameter to query string if disableCaching = true
12280 prepareUrl : function(url){
12281 if(this.disableCaching){
12282 var append = "_dc=" + (new Date().getTime());
12283 if(url.indexOf("?") !== -1){
12284 url += "&" + append;
12286 url += "?" + append;
12295 processSuccess : function(response){
12296 this.transaction = null;
12297 if(response.argument.form && response.argument.reset){
12298 try{ // put in try/catch since some older FF releases had problems with this
12299 response.argument.form.reset();
12302 if(this.loadScripts){
12303 this.renderer.render(this.el, response, this,
12304 this.updateComplete.createDelegate(this, [response]));
12306 this.renderer.render(this.el, response, this);
12307 this.updateComplete(response);
12311 updateComplete : function(response){
12312 this.fireEvent("update", this.el, response);
12313 if(typeof response.argument.callback == "function"){
12314 response.argument.callback(this.el, true, response);
12321 processFailure : function(response){
12322 this.transaction = null;
12323 this.fireEvent("failure", this.el, response);
12324 if(typeof response.argument.callback == "function"){
12325 response.argument.callback(this.el, false, response);
12330 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12331 * @param {Object} renderer The object implementing the render() method
12333 setRenderer : function(renderer){
12334 this.renderer = renderer;
12337 getRenderer : function(){
12338 return this.renderer;
12342 * Set the defaultUrl used for updates
12343 * @param {String/Function} defaultUrl The url or a function to call to get the url
12345 setDefaultUrl : function(defaultUrl){
12346 this.defaultUrl = defaultUrl;
12350 * Aborts the executing transaction
12352 abort : function(){
12353 if(this.transaction){
12354 Roo.Ajax.abort(this.transaction);
12359 * Returns true if an update is in progress
12360 * @return {Boolean}
12362 isUpdating : function(){
12363 if(this.transaction){
12364 return Roo.Ajax.isLoading(this.transaction);
12371 * @class Roo.UpdateManager.defaults
12372 * @static (not really - but it helps the doc tool)
12373 * The defaults collection enables customizing the default properties of UpdateManager
12375 Roo.UpdateManager.defaults = {
12377 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12383 * True to process scripts by default (Defaults to false).
12386 loadScripts : false,
12389 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12392 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12394 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12397 disableCaching : false,
12399 * Whether to show indicatorText when loading (Defaults to true).
12402 showLoadIndicator : true,
12404 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12407 indicatorText : '<div class="loading-indicator">Loading...</div>'
12411 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12413 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12414 * @param {String/HTMLElement/Roo.Element} el The element to update
12415 * @param {String} url The url
12416 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12417 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12420 * @member Roo.UpdateManager
12422 Roo.UpdateManager.updateElement = function(el, url, params, options){
12423 var um = Roo.get(el, true).getUpdateManager();
12424 Roo.apply(um, options);
12425 um.update(url, params, options ? options.callback : null);
12427 // alias for backwards compat
12428 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12430 * @class Roo.UpdateManager.BasicRenderer
12431 * Default Content renderer. Updates the elements innerHTML with the responseText.
12433 Roo.UpdateManager.BasicRenderer = function(){};
12435 Roo.UpdateManager.BasicRenderer.prototype = {
12437 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12438 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12439 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12440 * @param {Roo.Element} el The element being rendered
12441 * @param {Object} response The YUI Connect response object
12442 * @param {UpdateManager} updateManager The calling update manager
12443 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12445 render : function(el, response, updateManager, callback){
12446 el.update(response.responseText, updateManager.loadScripts, callback);
12452 * (c)) Alan Knowles
12458 * @class Roo.DomTemplate
12459 * @extends Roo.Template
12460 * An effort at a dom based template engine..
12462 * Similar to XTemplate, except it uses dom parsing to create the template..
12464 * Supported features:
12469 {a_variable} - output encoded.
12470 {a_variable.format:("Y-m-d")} - call a method on the variable
12471 {a_variable:raw} - unencoded output
12472 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12473 {a_variable:this.method_on_template(...)} - call a method on the template object.
12478 <div roo-for="a_variable or condition.."></div>
12479 <div roo-if="a_variable or condition"></div>
12480 <div roo-exec="some javascript"></div>
12481 <div roo-name="named_template"></div>
12486 Roo.DomTemplate = function()
12488 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12495 Roo.extend(Roo.DomTemplate, Roo.Template, {
12497 * id counter for sub templates.
12501 * flag to indicate if dom parser is inside a pre,
12502 * it will strip whitespace if not.
12507 * The various sub templates
12515 * basic tag replacing syntax
12518 * // you can fake an object call by doing this
12522 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12523 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12525 iterChild : function (node, method) {
12527 var oldPre = this.inPre;
12528 if (node.tagName == 'PRE') {
12531 for( var i = 0; i < node.childNodes.length; i++) {
12532 method.call(this, node.childNodes[i]);
12534 this.inPre = oldPre;
12540 * compile the template
12542 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12545 compile: function()
12549 // covert the html into DOM...
12553 doc = document.implementation.createHTMLDocument("");
12554 doc.documentElement.innerHTML = this.html ;
12555 div = doc.documentElement;
12557 // old IE... - nasty -- it causes all sorts of issues.. with
12558 // images getting pulled from server..
12559 div = document.createElement('div');
12560 div.innerHTML = this.html;
12562 //doc.documentElement.innerHTML = htmlBody
12568 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12570 var tpls = this.tpls;
12572 // create a top level template from the snippet..
12574 //Roo.log(div.innerHTML);
12581 body : div.innerHTML,
12594 Roo.each(tpls, function(tp){
12595 this.compileTpl(tp);
12596 this.tpls[tp.id] = tp;
12599 this.master = tpls[0];
12605 compileNode : function(node, istop) {
12610 // skip anything not a tag..
12611 if (node.nodeType != 1) {
12612 if (node.nodeType == 3 && !this.inPre) {
12613 // reduce white space..
12614 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12637 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12638 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12639 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12640 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12646 // just itterate children..
12647 this.iterChild(node,this.compileNode);
12650 tpl.uid = this.id++;
12651 tpl.value = node.getAttribute('roo-' + tpl.attr);
12652 node.removeAttribute('roo-'+ tpl.attr);
12653 if (tpl.attr != 'name') {
12654 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12655 node.parentNode.replaceChild(placeholder, node);
12658 var placeholder = document.createElement('span');
12659 placeholder.className = 'roo-tpl-' + tpl.value;
12660 node.parentNode.replaceChild(placeholder, node);
12663 // parent now sees '{domtplXXXX}
12664 this.iterChild(node,this.compileNode);
12666 // we should now have node body...
12667 var div = document.createElement('div');
12668 div.appendChild(node);
12670 // this has the unfortunate side effect of converting tagged attributes
12671 // eg. href="{...}" into %7C...%7D
12672 // this has been fixed by searching for those combo's although it's a bit hacky..
12675 tpl.body = div.innerHTML;
12682 switch (tpl.value) {
12683 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12684 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12685 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12690 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12694 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12698 tpl.id = tpl.value; // replace non characters???
12704 this.tpls.push(tpl);
12714 * Compile a segment of the template into a 'sub-template'
12720 compileTpl : function(tpl)
12722 var fm = Roo.util.Format;
12723 var useF = this.disableFormats !== true;
12725 var sep = Roo.isGecko ? "+\n" : ",\n";
12727 var undef = function(str) {
12728 Roo.debug && Roo.log("Property not found :" + str);
12732 //Roo.log(tpl.body);
12736 var fn = function(m, lbrace, name, format, args)
12739 //Roo.log(arguments);
12740 args = args ? args.replace(/\\'/g,"'") : args;
12741 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12742 if (typeof(format) == 'undefined') {
12743 format = 'htmlEncode';
12745 if (format == 'raw' ) {
12749 if(name.substr(0, 6) == 'domtpl'){
12750 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12753 // build an array of options to determine if value is undefined..
12755 // basically get 'xxxx.yyyy' then do
12756 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12757 // (function () { Roo.log("Property not found"); return ''; })() :
12762 Roo.each(name.split('.'), function(st) {
12763 lookfor += (lookfor.length ? '.': '') + st;
12764 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12767 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12770 if(format && useF){
12772 args = args ? ',' + args : "";
12774 if(format.substr(0, 5) != "this."){
12775 format = "fm." + format + '(';
12777 format = 'this.call("'+ format.substr(5) + '", ';
12781 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12784 if (args && args.length) {
12785 // called with xxyx.yuu:(test,test)
12787 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12789 // raw.. - :raw modifier..
12790 return "'"+ sep + udef_st + name + ")"+sep+"'";
12794 // branched to use + in gecko and [].join() in others
12796 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12797 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12800 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12801 body.push(tpl.body.replace(/(\r\n|\n)/g,
12802 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12803 body.push("'].join('');};};");
12804 body = body.join('');
12807 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12809 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12816 * same as applyTemplate, except it's done to one of the subTemplates
12817 * when using named templates, you can do:
12819 * var str = pl.applySubTemplate('your-name', values);
12822 * @param {Number} id of the template
12823 * @param {Object} values to apply to template
12824 * @param {Object} parent (normaly the instance of this object)
12826 applySubTemplate : function(id, values, parent)
12830 var t = this.tpls[id];
12834 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12835 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12839 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12846 if(t.execCall && t.execCall.call(this, values, parent)){
12850 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12856 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12857 parent = t.target ? values : parent;
12858 if(t.forCall && vs instanceof Array){
12860 for(var i = 0, len = vs.length; i < len; i++){
12862 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12864 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12866 //Roo.log(t.compiled);
12870 return buf.join('');
12873 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12878 return t.compiled.call(this, vs, parent);
12880 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12882 //Roo.log(t.compiled);
12890 applyTemplate : function(values){
12891 return this.master.compiled.call(this, values, {});
12892 //var s = this.subs;
12895 apply : function(){
12896 return this.applyTemplate.apply(this, arguments);
12901 Roo.DomTemplate.from = function(el){
12902 el = Roo.getDom(el);
12903 return new Roo.Domtemplate(el.value || el.innerHTML);
12906 * Ext JS Library 1.1.1
12907 * Copyright(c) 2006-2007, Ext JS, LLC.
12909 * Originally Released Under LGPL - original licence link has changed is not relivant.
12912 * <script type="text/javascript">
12916 * @class Roo.util.DelayedTask
12917 * Provides a convenient method of performing setTimeout where a new
12918 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12919 * You can use this class to buffer
12920 * the keypress events for a certain number of milliseconds, and perform only if they stop
12921 * for that amount of time.
12922 * @constructor The parameters to this constructor serve as defaults and are not required.
12923 * @param {Function} fn (optional) The default function to timeout
12924 * @param {Object} scope (optional) The default scope of that timeout
12925 * @param {Array} args (optional) The default Array of arguments
12927 Roo.util.DelayedTask = function(fn, scope, args){
12928 var id = null, d, t;
12930 var call = function(){
12931 var now = new Date().getTime();
12935 fn.apply(scope, args || []);
12939 * Cancels any pending timeout and queues a new one
12940 * @param {Number} delay The milliseconds to delay
12941 * @param {Function} newFn (optional) Overrides function passed to constructor
12942 * @param {Object} newScope (optional) Overrides scope passed to constructor
12943 * @param {Array} newArgs (optional) Overrides args passed to constructor
12945 this.delay = function(delay, newFn, newScope, newArgs){
12946 if(id && delay != d){
12950 t = new Date().getTime();
12952 scope = newScope || scope;
12953 args = newArgs || args;
12955 id = setInterval(call, d);
12960 * Cancel the last queued timeout
12962 this.cancel = function(){
12970 * Ext JS Library 1.1.1
12971 * Copyright(c) 2006-2007, Ext JS, LLC.
12973 * Originally Released Under LGPL - original licence link has changed is not relivant.
12976 * <script type="text/javascript">
12980 Roo.util.TaskRunner = function(interval){
12981 interval = interval || 10;
12982 var tasks = [], removeQueue = [];
12984 var running = false;
12986 var stopThread = function(){
12992 var startThread = function(){
12995 id = setInterval(runTasks, interval);
12999 var removeTask = function(task){
13000 removeQueue.push(task);
13006 var runTasks = function(){
13007 if(removeQueue.length > 0){
13008 for(var i = 0, len = removeQueue.length; i < len; i++){
13009 tasks.remove(removeQueue[i]);
13012 if(tasks.length < 1){
13017 var now = new Date().getTime();
13018 for(var i = 0, len = tasks.length; i < len; ++i){
13020 var itime = now - t.taskRunTime;
13021 if(t.interval <= itime){
13022 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13023 t.taskRunTime = now;
13024 if(rt === false || t.taskRunCount === t.repeat){
13029 if(t.duration && t.duration <= (now - t.taskStartTime)){
13036 * Queues a new task.
13037 * @param {Object} task
13039 this.start = function(task){
13041 task.taskStartTime = new Date().getTime();
13042 task.taskRunTime = 0;
13043 task.taskRunCount = 0;
13048 this.stop = function(task){
13053 this.stopAll = function(){
13055 for(var i = 0, len = tasks.length; i < len; i++){
13056 if(tasks[i].onStop){
13065 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13067 * Ext JS Library 1.1.1
13068 * Copyright(c) 2006-2007, Ext JS, LLC.
13070 * Originally Released Under LGPL - original licence link has changed is not relivant.
13073 * <script type="text/javascript">
13078 * @class Roo.util.MixedCollection
13079 * @extends Roo.util.Observable
13080 * A Collection class that maintains both numeric indexes and keys and exposes events.
13082 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13083 * collection (defaults to false)
13084 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13085 * and return the key value for that item. This is used when available to look up the key on items that
13086 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13087 * equivalent to providing an implementation for the {@link #getKey} method.
13089 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13097 * Fires when the collection is cleared.
13102 * Fires when an item is added to the collection.
13103 * @param {Number} index The index at which the item was added.
13104 * @param {Object} o The item added.
13105 * @param {String} key The key associated with the added item.
13110 * Fires when an item is replaced in the collection.
13111 * @param {String} key he key associated with the new added.
13112 * @param {Object} old The item being replaced.
13113 * @param {Object} new The new item.
13118 * Fires when an item is removed from the collection.
13119 * @param {Object} o The item being removed.
13120 * @param {String} key (optional) The key associated with the removed item.
13125 this.allowFunctions = allowFunctions === true;
13127 this.getKey = keyFn;
13129 Roo.util.MixedCollection.superclass.constructor.call(this);
13132 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13133 allowFunctions : false,
13136 * Adds an item to the collection.
13137 * @param {String} key The key to associate with the item
13138 * @param {Object} o The item to add.
13139 * @return {Object} The item added.
13141 add : function(key, o){
13142 if(arguments.length == 1){
13144 key = this.getKey(o);
13146 if(typeof key == "undefined" || key === null){
13148 this.items.push(o);
13149 this.keys.push(null);
13151 var old = this.map[key];
13153 return this.replace(key, o);
13156 this.items.push(o);
13158 this.keys.push(key);
13160 this.fireEvent("add", this.length-1, o, key);
13165 * MixedCollection has a generic way to fetch keys if you implement getKey.
13168 var mc = new Roo.util.MixedCollection();
13169 mc.add(someEl.dom.id, someEl);
13170 mc.add(otherEl.dom.id, otherEl);
13174 var mc = new Roo.util.MixedCollection();
13175 mc.getKey = function(el){
13181 // or via the constructor
13182 var mc = new Roo.util.MixedCollection(false, function(el){
13188 * @param o {Object} The item for which to find the key.
13189 * @return {Object} The key for the passed item.
13191 getKey : function(o){
13196 * Replaces an item in the collection.
13197 * @param {String} key The key associated with the item to replace, or the item to replace.
13198 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13199 * @return {Object} The new item.
13201 replace : function(key, o){
13202 if(arguments.length == 1){
13204 key = this.getKey(o);
13206 var old = this.item(key);
13207 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13208 return this.add(key, o);
13210 var index = this.indexOfKey(key);
13211 this.items[index] = o;
13213 this.fireEvent("replace", key, old, o);
13218 * Adds all elements of an Array or an Object to the collection.
13219 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13220 * an Array of values, each of which are added to the collection.
13222 addAll : function(objs){
13223 if(arguments.length > 1 || objs instanceof Array){
13224 var args = arguments.length > 1 ? arguments : objs;
13225 for(var i = 0, len = args.length; i < len; i++){
13229 for(var key in objs){
13230 if(this.allowFunctions || typeof objs[key] != "function"){
13231 this.add(key, objs[key]);
13238 * Executes the specified function once for every item in the collection, passing each
13239 * item as the first and only parameter. returning false from the function will stop the iteration.
13240 * @param {Function} fn The function to execute for each item.
13241 * @param {Object} scope (optional) The scope in which to execute the function.
13243 each : function(fn, scope){
13244 var items = [].concat(this.items); // each safe for removal
13245 for(var i = 0, len = items.length; i < len; i++){
13246 if(fn.call(scope || items[i], items[i], i, len) === false){
13253 * Executes the specified function once for every key in the collection, passing each
13254 * key, and its associated item as the first two parameters.
13255 * @param {Function} fn The function to execute for each item.
13256 * @param {Object} scope (optional) The scope in which to execute the function.
13258 eachKey : function(fn, scope){
13259 for(var i = 0, len = this.keys.length; i < len; i++){
13260 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13265 * Returns the first item in the collection which elicits a true return value from the
13266 * passed selection function.
13267 * @param {Function} fn The selection function to execute for each item.
13268 * @param {Object} scope (optional) The scope in which to execute the function.
13269 * @return {Object} The first item in the collection which returned true from the selection function.
13271 find : function(fn, scope){
13272 for(var i = 0, len = this.items.length; i < len; i++){
13273 if(fn.call(scope || window, this.items[i], this.keys[i])){
13274 return this.items[i];
13281 * Inserts an item at the specified index in the collection.
13282 * @param {Number} index The index to insert the item at.
13283 * @param {String} key The key to associate with the new item, or the item itself.
13284 * @param {Object} o (optional) If the second parameter was a key, the new item.
13285 * @return {Object} The item inserted.
13287 insert : function(index, key, o){
13288 if(arguments.length == 2){
13290 key = this.getKey(o);
13292 if(index >= this.length){
13293 return this.add(key, o);
13296 this.items.splice(index, 0, o);
13297 if(typeof key != "undefined" && key != null){
13300 this.keys.splice(index, 0, key);
13301 this.fireEvent("add", index, o, key);
13306 * Removed an item from the collection.
13307 * @param {Object} o The item to remove.
13308 * @return {Object} The item removed.
13310 remove : function(o){
13311 return this.removeAt(this.indexOf(o));
13315 * Remove an item from a specified index in the collection.
13316 * @param {Number} index The index within the collection of the item to remove.
13318 removeAt : function(index){
13319 if(index < this.length && index >= 0){
13321 var o = this.items[index];
13322 this.items.splice(index, 1);
13323 var key = this.keys[index];
13324 if(typeof key != "undefined"){
13325 delete this.map[key];
13327 this.keys.splice(index, 1);
13328 this.fireEvent("remove", o, key);
13333 * Removed an item associated with the passed key fom the collection.
13334 * @param {String} key The key of the item to remove.
13336 removeKey : function(key){
13337 return this.removeAt(this.indexOfKey(key));
13341 * Returns the number of items in the collection.
13342 * @return {Number} the number of items in the collection.
13344 getCount : function(){
13345 return this.length;
13349 * Returns index within the collection of the passed Object.
13350 * @param {Object} o The item to find the index of.
13351 * @return {Number} index of the item.
13353 indexOf : function(o){
13354 if(!this.items.indexOf){
13355 for(var i = 0, len = this.items.length; i < len; i++){
13356 if(this.items[i] == o) {
13362 return this.items.indexOf(o);
13367 * Returns index within the collection of the passed key.
13368 * @param {String} key The key to find the index of.
13369 * @return {Number} index of the key.
13371 indexOfKey : function(key){
13372 if(!this.keys.indexOf){
13373 for(var i = 0, len = this.keys.length; i < len; i++){
13374 if(this.keys[i] == key) {
13380 return this.keys.indexOf(key);
13385 * Returns the item associated with the passed key OR index. Key has priority over index.
13386 * @param {String/Number} key The key or index of the item.
13387 * @return {Object} The item associated with the passed key.
13389 item : function(key){
13390 if (key === 'length') {
13393 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13394 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13398 * Returns the item at the specified index.
13399 * @param {Number} index The index of the item.
13402 itemAt : function(index){
13403 return this.items[index];
13407 * Returns the item associated with the passed key.
13408 * @param {String/Number} key The key of the item.
13409 * @return {Object} The item associated with the passed key.
13411 key : function(key){
13412 return this.map[key];
13416 * Returns true if the collection contains the passed Object as an item.
13417 * @param {Object} o The Object to look for in the collection.
13418 * @return {Boolean} True if the collection contains the Object as an item.
13420 contains : function(o){
13421 return this.indexOf(o) != -1;
13425 * Returns true if the collection contains the passed Object as a key.
13426 * @param {String} key The key to look for in the collection.
13427 * @return {Boolean} True if the collection contains the Object as a key.
13429 containsKey : function(key){
13430 return typeof this.map[key] != "undefined";
13434 * Removes all items from the collection.
13436 clear : function(){
13441 this.fireEvent("clear");
13445 * Returns the first item in the collection.
13446 * @return {Object} the first item in the collection..
13448 first : function(){
13449 return this.items[0];
13453 * Returns the last item in the collection.
13454 * @return {Object} the last item in the collection..
13457 return this.items[this.length-1];
13460 _sort : function(property, dir, fn){
13461 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13462 fn = fn || function(a, b){
13465 var c = [], k = this.keys, items = this.items;
13466 for(var i = 0, len = items.length; i < len; i++){
13467 c[c.length] = {key: k[i], value: items[i], index: i};
13469 c.sort(function(a, b){
13470 var v = fn(a[property], b[property]) * dsc;
13472 v = (a.index < b.index ? -1 : 1);
13476 for(var i = 0, len = c.length; i < len; i++){
13477 items[i] = c[i].value;
13480 this.fireEvent("sort", this);
13484 * Sorts this collection with the passed comparison function
13485 * @param {String} direction (optional) "ASC" or "DESC"
13486 * @param {Function} fn (optional) comparison function
13488 sort : function(dir, fn){
13489 this._sort("value", dir, fn);
13493 * Sorts this collection by keys
13494 * @param {String} direction (optional) "ASC" or "DESC"
13495 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13497 keySort : function(dir, fn){
13498 this._sort("key", dir, fn || function(a, b){
13499 return String(a).toUpperCase()-String(b).toUpperCase();
13504 * Returns a range of items in this collection
13505 * @param {Number} startIndex (optional) defaults to 0
13506 * @param {Number} endIndex (optional) default to the last item
13507 * @return {Array} An array of items
13509 getRange : function(start, end){
13510 var items = this.items;
13511 if(items.length < 1){
13514 start = start || 0;
13515 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13518 for(var i = start; i <= end; i++) {
13519 r[r.length] = items[i];
13522 for(var i = start; i >= end; i--) {
13523 r[r.length] = items[i];
13530 * Filter the <i>objects</i> in this collection by a specific property.
13531 * Returns a new collection that has been filtered.
13532 * @param {String} property A property on your objects
13533 * @param {String/RegExp} value Either string that the property values
13534 * should start with or a RegExp to test against the property
13535 * @return {MixedCollection} The new filtered collection
13537 filter : function(property, value){
13538 if(!value.exec){ // not a regex
13539 value = String(value);
13540 if(value.length == 0){
13541 return this.clone();
13543 value = new RegExp("^" + Roo.escapeRe(value), "i");
13545 return this.filterBy(function(o){
13546 return o && value.test(o[property]);
13551 * Filter by a function. * Returns a new collection that has been filtered.
13552 * The passed function will be called with each
13553 * object in the collection. If the function returns true, the value is included
13554 * otherwise it is filtered.
13555 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13556 * @param {Object} scope (optional) The scope of the function (defaults to this)
13557 * @return {MixedCollection} The new filtered collection
13559 filterBy : function(fn, scope){
13560 var r = new Roo.util.MixedCollection();
13561 r.getKey = this.getKey;
13562 var k = this.keys, it = this.items;
13563 for(var i = 0, len = it.length; i < len; i++){
13564 if(fn.call(scope||this, it[i], k[i])){
13565 r.add(k[i], it[i]);
13572 * Creates a duplicate of this collection
13573 * @return {MixedCollection}
13575 clone : function(){
13576 var r = new Roo.util.MixedCollection();
13577 var k = this.keys, it = this.items;
13578 for(var i = 0, len = it.length; i < len; i++){
13579 r.add(k[i], it[i]);
13581 r.getKey = this.getKey;
13586 * Returns the item associated with the passed key or index.
13588 * @param {String/Number} key The key or index of the item.
13589 * @return {Object} The item associated with the passed key.
13591 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13593 * Ext JS Library 1.1.1
13594 * Copyright(c) 2006-2007, Ext JS, LLC.
13596 * Originally Released Under LGPL - original licence link has changed is not relivant.
13599 * <script type="text/javascript">
13602 * @class Roo.util.JSON
13603 * Modified version of Douglas Crockford"s json.js that doesn"t
13604 * mess with the Object prototype
13605 * http://www.json.org/js.html
13608 Roo.util.JSON = new (function(){
13609 var useHasOwn = {}.hasOwnProperty ? true : false;
13611 // crashes Safari in some instances
13612 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13614 var pad = function(n) {
13615 return n < 10 ? "0" + n : n;
13628 var encodeString = function(s){
13629 if (/["\\\x00-\x1f]/.test(s)) {
13630 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13635 c = b.charCodeAt();
13637 Math.floor(c / 16).toString(16) +
13638 (c % 16).toString(16);
13641 return '"' + s + '"';
13644 var encodeArray = function(o){
13645 var a = ["["], b, i, l = o.length, v;
13646 for (i = 0; i < l; i += 1) {
13648 switch (typeof v) {
13657 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13665 var encodeDate = function(o){
13666 return '"' + o.getFullYear() + "-" +
13667 pad(o.getMonth() + 1) + "-" +
13668 pad(o.getDate()) + "T" +
13669 pad(o.getHours()) + ":" +
13670 pad(o.getMinutes()) + ":" +
13671 pad(o.getSeconds()) + '"';
13675 * Encodes an Object, Array or other value
13676 * @param {Mixed} o The variable to encode
13677 * @return {String} The JSON string
13679 this.encode = function(o)
13681 // should this be extended to fully wrap stringify..
13683 if(typeof o == "undefined" || o === null){
13685 }else if(o instanceof Array){
13686 return encodeArray(o);
13687 }else if(o instanceof Date){
13688 return encodeDate(o);
13689 }else if(typeof o == "string"){
13690 return encodeString(o);
13691 }else if(typeof o == "number"){
13692 return isFinite(o) ? String(o) : "null";
13693 }else if(typeof o == "boolean"){
13696 var a = ["{"], b, i, v;
13698 if(!useHasOwn || o.hasOwnProperty(i)) {
13700 switch (typeof v) {
13709 a.push(this.encode(i), ":",
13710 v === null ? "null" : this.encode(v));
13721 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13722 * @param {String} json The JSON string
13723 * @return {Object} The resulting object
13725 this.decode = function(json){
13727 return /** eval:var:json */ eval("(" + json + ')');
13731 * Shorthand for {@link Roo.util.JSON#encode}
13732 * @member Roo encode
13734 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13736 * Shorthand for {@link Roo.util.JSON#decode}
13737 * @member Roo decode
13739 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13742 * Ext JS Library 1.1.1
13743 * Copyright(c) 2006-2007, Ext JS, LLC.
13745 * Originally Released Under LGPL - original licence link has changed is not relivant.
13748 * <script type="text/javascript">
13752 * @class Roo.util.Format
13753 * Reusable data formatting functions
13756 Roo.util.Format = function(){
13757 var trimRe = /^\s+|\s+$/g;
13760 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13761 * @param {String} value The string to truncate
13762 * @param {Number} length The maximum length to allow before truncating
13763 * @return {String} The converted text
13765 ellipsis : function(value, len){
13766 if(value && value.length > len){
13767 return value.substr(0, len-3)+"...";
13773 * Checks a reference and converts it to empty string if it is undefined
13774 * @param {Mixed} value Reference to check
13775 * @return {Mixed} Empty string if converted, otherwise the original value
13777 undef : function(value){
13778 return typeof value != "undefined" ? value : "";
13782 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13783 * @param {String} value The string to encode
13784 * @return {String} The encoded text
13786 htmlEncode : function(value){
13787 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13791 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13792 * @param {String} value The string to decode
13793 * @return {String} The decoded text
13795 htmlDecode : function(value){
13796 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13800 * Trims any whitespace from either side of a string
13801 * @param {String} value The text to trim
13802 * @return {String} The trimmed text
13804 trim : function(value){
13805 return String(value).replace(trimRe, "");
13809 * Returns a substring from within an original string
13810 * @param {String} value The original text
13811 * @param {Number} start The start index of the substring
13812 * @param {Number} length The length of the substring
13813 * @return {String} The substring
13815 substr : function(value, start, length){
13816 return String(value).substr(start, length);
13820 * Converts a string to all lower case letters
13821 * @param {String} value The text to convert
13822 * @return {String} The converted text
13824 lowercase : function(value){
13825 return String(value).toLowerCase();
13829 * Converts a string to all upper case letters
13830 * @param {String} value The text to convert
13831 * @return {String} The converted text
13833 uppercase : function(value){
13834 return String(value).toUpperCase();
13838 * Converts the first character only of a string to upper case
13839 * @param {String} value The text to convert
13840 * @return {String} The converted text
13842 capitalize : function(value){
13843 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13847 call : function(value, fn){
13848 if(arguments.length > 2){
13849 var args = Array.prototype.slice.call(arguments, 2);
13850 args.unshift(value);
13852 return /** eval:var:value */ eval(fn).apply(window, args);
13854 /** eval:var:value */
13855 return /** eval:var:value */ eval(fn).call(window, value);
13861 * safer version of Math.toFixed..??/
13862 * @param {Number/String} value The numeric value to format
13863 * @param {Number/String} value Decimal places
13864 * @return {String} The formatted currency string
13866 toFixed : function(v, n)
13868 // why not use to fixed - precision is buggered???
13870 return Math.round(v-0);
13872 var fact = Math.pow(10,n+1);
13873 v = (Math.round((v-0)*fact))/fact;
13874 var z = (''+fact).substring(2);
13875 if (v == Math.floor(v)) {
13876 return Math.floor(v) + '.' + z;
13879 // now just padd decimals..
13880 var ps = String(v).split('.');
13881 var fd = (ps[1] + z);
13882 var r = fd.substring(0,n);
13883 var rm = fd.substring(n);
13885 return ps[0] + '.' + r;
13887 r*=1; // turn it into a number;
13889 if (String(r).length != n) {
13892 r = String(r).substring(1); // chop the end off.
13895 return ps[0] + '.' + r;
13900 * Format a number as US currency
13901 * @param {Number/String} value The numeric value to format
13902 * @return {String} The formatted currency string
13904 usMoney : function(v){
13905 return '$' + Roo.util.Format.number(v);
13910 * eventually this should probably emulate php's number_format
13911 * @param {Number/String} value The numeric value to format
13912 * @param {Number} decimals number of decimal places
13913 * @param {String} delimiter for thousands (default comma)
13914 * @return {String} The formatted currency string
13916 number : function(v, decimals, thousandsDelimiter)
13918 // multiply and round.
13919 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13920 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13922 var mul = Math.pow(10, decimals);
13923 var zero = String(mul).substring(1);
13924 v = (Math.round((v-0)*mul))/mul;
13926 // if it's '0' number.. then
13928 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13930 var ps = v.split('.');
13933 var r = /(\d+)(\d{3})/;
13936 if(thousandsDelimiter.length != 0) {
13937 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13942 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13943 // does not have decimals
13944 (decimals ? ('.' + zero) : '');
13947 return whole + sub ;
13951 * Parse a value into a formatted date using the specified format pattern.
13952 * @param {Mixed} value The value to format
13953 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13954 * @return {String} The formatted date string
13956 date : function(v, format){
13960 if(!(v instanceof Date)){
13961 v = new Date(Date.parse(v));
13963 return v.dateFormat(format || Roo.util.Format.defaults.date);
13967 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13968 * @param {String} format Any valid date format string
13969 * @return {Function} The date formatting function
13971 dateRenderer : function(format){
13972 return function(v){
13973 return Roo.util.Format.date(v, format);
13978 stripTagsRE : /<\/?[^>]+>/gi,
13981 * Strips all HTML tags
13982 * @param {Mixed} value The text from which to strip tags
13983 * @return {String} The stripped text
13985 stripTags : function(v){
13986 return !v ? v : String(v).replace(this.stripTagsRE, "");
13990 Roo.util.Format.defaults = {
13994 * Ext JS Library 1.1.1
13995 * Copyright(c) 2006-2007, Ext JS, LLC.
13997 * Originally Released Under LGPL - original licence link has changed is not relivant.
14000 * <script type="text/javascript">
14007 * @class Roo.MasterTemplate
14008 * @extends Roo.Template
14009 * Provides a template that can have child templates. The syntax is:
14011 var t = new Roo.MasterTemplate(
14012 '<select name="{name}">',
14013 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14016 t.add('options', {value: 'foo', text: 'bar'});
14017 // or you can add multiple child elements in one shot
14018 t.addAll('options', [
14019 {value: 'foo', text: 'bar'},
14020 {value: 'foo2', text: 'bar2'},
14021 {value: 'foo3', text: 'bar3'}
14023 // then append, applying the master template values
14024 t.append('my-form', {name: 'my-select'});
14026 * A name attribute for the child template is not required if you have only one child
14027 * template or you want to refer to them by index.
14029 Roo.MasterTemplate = function(){
14030 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14031 this.originalHtml = this.html;
14033 var m, re = this.subTemplateRe;
14036 while(m = re.exec(this.html)){
14037 var name = m[1], content = m[2];
14042 tpl : new Roo.Template(content)
14045 st[name] = st[subIndex];
14047 st[subIndex].tpl.compile();
14048 st[subIndex].tpl.call = this.call.createDelegate(this);
14051 this.subCount = subIndex;
14054 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14056 * The regular expression used to match sub templates
14060 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14063 * Applies the passed values to a child template.
14064 * @param {String/Number} name (optional) The name or index of the child template
14065 * @param {Array/Object} values The values to be applied to the template
14066 * @return {MasterTemplate} this
14068 add : function(name, values){
14069 if(arguments.length == 1){
14070 values = arguments[0];
14073 var s = this.subs[name];
14074 s.buffer[s.buffer.length] = s.tpl.apply(values);
14079 * Applies all the passed values to a child template.
14080 * @param {String/Number} name (optional) The name or index of the child template
14081 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14082 * @param {Boolean} reset (optional) True to reset the template first
14083 * @return {MasterTemplate} this
14085 fill : function(name, values, reset){
14087 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14095 for(var i = 0, len = values.length; i < len; i++){
14096 this.add(name, values[i]);
14102 * Resets the template for reuse
14103 * @return {MasterTemplate} this
14105 reset : function(){
14107 for(var i = 0; i < this.subCount; i++){
14113 applyTemplate : function(values){
14115 var replaceIndex = -1;
14116 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14117 return s[++replaceIndex].buffer.join("");
14119 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14122 apply : function(){
14123 return this.applyTemplate.apply(this, arguments);
14126 compile : function(){return this;}
14130 * Alias for fill().
14133 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14135 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14136 * var tpl = Roo.MasterTemplate.from('element-id');
14137 * @param {String/HTMLElement} el
14138 * @param {Object} config
14141 Roo.MasterTemplate.from = function(el, config){
14142 el = Roo.getDom(el);
14143 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14146 * Ext JS Library 1.1.1
14147 * Copyright(c) 2006-2007, Ext JS, LLC.
14149 * Originally Released Under LGPL - original licence link has changed is not relivant.
14152 * <script type="text/javascript">
14157 * @class Roo.util.CSS
14158 * Utility class for manipulating CSS rules
14161 Roo.util.CSS = function(){
14163 var doc = document;
14165 var camelRe = /(-[a-z])/gi;
14166 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14170 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14171 * tag and appended to the HEAD of the document.
14172 * @param {String|Object} cssText The text containing the css rules
14173 * @param {String} id An id to add to the stylesheet for later removal
14174 * @return {StyleSheet}
14176 createStyleSheet : function(cssText, id){
14178 var head = doc.getElementsByTagName("head")[0];
14179 var nrules = doc.createElement("style");
14180 nrules.setAttribute("type", "text/css");
14182 nrules.setAttribute("id", id);
14184 if (typeof(cssText) != 'string') {
14185 // support object maps..
14186 // not sure if this a good idea..
14187 // perhaps it should be merged with the general css handling
14188 // and handle js style props.
14189 var cssTextNew = [];
14190 for(var n in cssText) {
14192 for(var k in cssText[n]) {
14193 citems.push( k + ' : ' +cssText[n][k] + ';' );
14195 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14198 cssText = cssTextNew.join("\n");
14204 head.appendChild(nrules);
14205 ss = nrules.styleSheet;
14206 ss.cssText = cssText;
14209 nrules.appendChild(doc.createTextNode(cssText));
14211 nrules.cssText = cssText;
14213 head.appendChild(nrules);
14214 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14216 this.cacheStyleSheet(ss);
14221 * Removes a style or link tag by id
14222 * @param {String} id The id of the tag
14224 removeStyleSheet : function(id){
14225 var existing = doc.getElementById(id);
14227 existing.parentNode.removeChild(existing);
14232 * Dynamically swaps an existing stylesheet reference for a new one
14233 * @param {String} id The id of an existing link tag to remove
14234 * @param {String} url The href of the new stylesheet to include
14236 swapStyleSheet : function(id, url){
14237 this.removeStyleSheet(id);
14238 var ss = doc.createElement("link");
14239 ss.setAttribute("rel", "stylesheet");
14240 ss.setAttribute("type", "text/css");
14241 ss.setAttribute("id", id);
14242 ss.setAttribute("href", url);
14243 doc.getElementsByTagName("head")[0].appendChild(ss);
14247 * Refresh the rule cache if you have dynamically added stylesheets
14248 * @return {Object} An object (hash) of rules indexed by selector
14250 refreshCache : function(){
14251 return this.getRules(true);
14255 cacheStyleSheet : function(stylesheet){
14259 try{// try catch for cross domain access issue
14260 var ssRules = stylesheet.cssRules || stylesheet.rules;
14261 for(var j = ssRules.length-1; j >= 0; --j){
14262 rules[ssRules[j].selectorText] = ssRules[j];
14268 * Gets all css rules for the document
14269 * @param {Boolean} refreshCache true to refresh the internal cache
14270 * @return {Object} An object (hash) of rules indexed by selector
14272 getRules : function(refreshCache){
14273 if(rules == null || refreshCache){
14275 var ds = doc.styleSheets;
14276 for(var i =0, len = ds.length; i < len; i++){
14278 this.cacheStyleSheet(ds[i]);
14286 * Gets an an individual CSS rule by selector(s)
14287 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14288 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14289 * @return {CSSRule} The CSS rule or null if one is not found
14291 getRule : function(selector, refreshCache){
14292 var rs = this.getRules(refreshCache);
14293 if(!(selector instanceof Array)){
14294 return rs[selector];
14296 for(var i = 0; i < selector.length; i++){
14297 if(rs[selector[i]]){
14298 return rs[selector[i]];
14306 * Updates a rule property
14307 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14308 * @param {String} property The css property
14309 * @param {String} value The new value for the property
14310 * @return {Boolean} true If a rule was found and updated
14312 updateRule : function(selector, property, value){
14313 if(!(selector instanceof Array)){
14314 var rule = this.getRule(selector);
14316 rule.style[property.replace(camelRe, camelFn)] = value;
14320 for(var i = 0; i < selector.length; i++){
14321 if(this.updateRule(selector[i], property, value)){
14331 * Ext JS Library 1.1.1
14332 * Copyright(c) 2006-2007, Ext JS, LLC.
14334 * Originally Released Under LGPL - original licence link has changed is not relivant.
14337 * <script type="text/javascript">
14343 * @class Roo.util.ClickRepeater
14344 * @extends Roo.util.Observable
14346 * A wrapper class which can be applied to any element. Fires a "click" event while the
14347 * mouse is pressed. The interval between firings may be specified in the config but
14348 * defaults to 10 milliseconds.
14350 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14352 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14353 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14354 * Similar to an autorepeat key delay.
14355 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14356 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14357 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14358 * "interval" and "delay" are ignored. "immediate" is honored.
14359 * @cfg {Boolean} preventDefault True to prevent the default click event
14360 * @cfg {Boolean} stopDefault True to stop the default click event
14363 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14364 * 2007-02-02 jvs Renamed to ClickRepeater
14365 * 2007-02-03 jvs Modifications for FF Mac and Safari
14368 * @param {String/HTMLElement/Element} el The element to listen on
14369 * @param {Object} config
14371 Roo.util.ClickRepeater = function(el, config)
14373 this.el = Roo.get(el);
14374 this.el.unselectable();
14376 Roo.apply(this, config);
14381 * Fires when the mouse button is depressed.
14382 * @param {Roo.util.ClickRepeater} this
14384 "mousedown" : true,
14387 * Fires on a specified interval during the time the element is pressed.
14388 * @param {Roo.util.ClickRepeater} this
14393 * Fires when the mouse key is released.
14394 * @param {Roo.util.ClickRepeater} this
14399 this.el.on("mousedown", this.handleMouseDown, this);
14400 if(this.preventDefault || this.stopDefault){
14401 this.el.on("click", function(e){
14402 if(this.preventDefault){
14403 e.preventDefault();
14405 if(this.stopDefault){
14411 // allow inline handler
14413 this.on("click", this.handler, this.scope || this);
14416 Roo.util.ClickRepeater.superclass.constructor.call(this);
14419 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14422 preventDefault : true,
14423 stopDefault : false,
14427 handleMouseDown : function(){
14428 clearTimeout(this.timer);
14430 if(this.pressClass){
14431 this.el.addClass(this.pressClass);
14433 this.mousedownTime = new Date();
14435 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14436 this.el.on("mouseout", this.handleMouseOut, this);
14438 this.fireEvent("mousedown", this);
14439 this.fireEvent("click", this);
14441 this.timer = this.click.defer(this.delay || this.interval, this);
14445 click : function(){
14446 this.fireEvent("click", this);
14447 this.timer = this.click.defer(this.getInterval(), this);
14451 getInterval: function(){
14452 if(!this.accelerate){
14453 return this.interval;
14455 var pressTime = this.mousedownTime.getElapsed();
14456 if(pressTime < 500){
14458 }else if(pressTime < 1700){
14460 }else if(pressTime < 2600){
14462 }else if(pressTime < 3500){
14464 }else if(pressTime < 4400){
14466 }else if(pressTime < 5300){
14468 }else if(pressTime < 6200){
14476 handleMouseOut : function(){
14477 clearTimeout(this.timer);
14478 if(this.pressClass){
14479 this.el.removeClass(this.pressClass);
14481 this.el.on("mouseover", this.handleMouseReturn, this);
14485 handleMouseReturn : function(){
14486 this.el.un("mouseover", this.handleMouseReturn);
14487 if(this.pressClass){
14488 this.el.addClass(this.pressClass);
14494 handleMouseUp : function(){
14495 clearTimeout(this.timer);
14496 this.el.un("mouseover", this.handleMouseReturn);
14497 this.el.un("mouseout", this.handleMouseOut);
14498 Roo.get(document).un("mouseup", this.handleMouseUp);
14499 this.el.removeClass(this.pressClass);
14500 this.fireEvent("mouseup", this);
14504 * Ext JS Library 1.1.1
14505 * Copyright(c) 2006-2007, Ext JS, LLC.
14507 * Originally Released Under LGPL - original licence link has changed is not relivant.
14510 * <script type="text/javascript">
14515 * @class Roo.KeyNav
14516 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14517 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14518 * way to implement custom navigation schemes for any UI component.</p>
14519 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14520 * pageUp, pageDown, del, home, end. Usage:</p>
14522 var nav = new Roo.KeyNav("my-element", {
14523 "left" : function(e){
14524 this.moveLeft(e.ctrlKey);
14526 "right" : function(e){
14527 this.moveRight(e.ctrlKey);
14529 "enter" : function(e){
14536 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14537 * @param {Object} config The config
14539 Roo.KeyNav = function(el, config){
14540 this.el = Roo.get(el);
14541 Roo.apply(this, config);
14542 if(!this.disabled){
14543 this.disabled = true;
14548 Roo.KeyNav.prototype = {
14550 * @cfg {Boolean} disabled
14551 * True to disable this KeyNav instance (defaults to false)
14555 * @cfg {String} defaultEventAction
14556 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14557 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14558 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14560 defaultEventAction: "stopEvent",
14562 * @cfg {Boolean} forceKeyDown
14563 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14564 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14565 * handle keydown instead of keypress.
14567 forceKeyDown : false,
14570 prepareEvent : function(e){
14571 var k = e.getKey();
14572 var h = this.keyToHandler[k];
14573 //if(h && this[h]){
14574 // e.stopPropagation();
14576 if(Roo.isSafari && h && k >= 37 && k <= 40){
14582 relay : function(e){
14583 var k = e.getKey();
14584 var h = this.keyToHandler[k];
14586 if(this.doRelay(e, this[h], h) !== true){
14587 e[this.defaultEventAction]();
14593 doRelay : function(e, h, hname){
14594 return h.call(this.scope || this, e);
14597 // possible handlers
14611 // quick lookup hash
14628 * Enable this KeyNav
14630 enable: function(){
14632 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14633 // the EventObject will normalize Safari automatically
14634 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14635 this.el.on("keydown", this.relay, this);
14637 this.el.on("keydown", this.prepareEvent, this);
14638 this.el.on("keypress", this.relay, this);
14640 this.disabled = false;
14645 * Disable this KeyNav
14647 disable: function(){
14648 if(!this.disabled){
14649 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14650 this.el.un("keydown", this.relay);
14652 this.el.un("keydown", this.prepareEvent);
14653 this.el.un("keypress", this.relay);
14655 this.disabled = true;
14660 * Ext JS Library 1.1.1
14661 * Copyright(c) 2006-2007, Ext JS, LLC.
14663 * Originally Released Under LGPL - original licence link has changed is not relivant.
14666 * <script type="text/javascript">
14671 * @class Roo.KeyMap
14672 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14673 * The constructor accepts the same config object as defined by {@link #addBinding}.
14674 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14675 * combination it will call the function with this signature (if the match is a multi-key
14676 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14677 * A KeyMap can also handle a string representation of keys.<br />
14680 // map one key by key code
14681 var map = new Roo.KeyMap("my-element", {
14682 key: 13, // or Roo.EventObject.ENTER
14687 // map multiple keys to one action by string
14688 var map = new Roo.KeyMap("my-element", {
14694 // map multiple keys to multiple actions by strings and array of codes
14695 var map = new Roo.KeyMap("my-element", [
14698 fn: function(){ alert("Return was pressed"); }
14701 fn: function(){ alert('a, b or c was pressed'); }
14706 fn: function(){ alert('Control + shift + tab was pressed.'); }
14710 * <b>Note: A KeyMap starts enabled</b>
14712 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14713 * @param {Object} config The config (see {@link #addBinding})
14714 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14716 Roo.KeyMap = function(el, config, eventName){
14717 this.el = Roo.get(el);
14718 this.eventName = eventName || "keydown";
14719 this.bindings = [];
14721 this.addBinding(config);
14726 Roo.KeyMap.prototype = {
14728 * True to stop the event from bubbling and prevent the default browser action if the
14729 * key was handled by the KeyMap (defaults to false)
14735 * Add a new binding to this KeyMap. The following config object properties are supported:
14737 Property Type Description
14738 ---------- --------------- ----------------------------------------------------------------------
14739 key String/Array A single keycode or an array of keycodes to handle
14740 shift Boolean True to handle key only when shift is pressed (defaults to false)
14741 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14742 alt Boolean True to handle key only when alt is pressed (defaults to false)
14743 fn Function The function to call when KeyMap finds the expected key combination
14744 scope Object The scope of the callback function
14750 var map = new Roo.KeyMap(document, {
14751 key: Roo.EventObject.ENTER,
14756 //Add a new binding to the existing KeyMap later
14764 * @param {Object/Array} config A single KeyMap config or an array of configs
14766 addBinding : function(config){
14767 if(config instanceof Array){
14768 for(var i = 0, len = config.length; i < len; i++){
14769 this.addBinding(config[i]);
14773 var keyCode = config.key,
14774 shift = config.shift,
14775 ctrl = config.ctrl,
14778 scope = config.scope;
14779 if(typeof keyCode == "string"){
14781 var keyString = keyCode.toUpperCase();
14782 for(var j = 0, len = keyString.length; j < len; j++){
14783 ks.push(keyString.charCodeAt(j));
14787 var keyArray = keyCode instanceof Array;
14788 var handler = function(e){
14789 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14790 var k = e.getKey();
14792 for(var i = 0, len = keyCode.length; i < len; i++){
14793 if(keyCode[i] == k){
14794 if(this.stopEvent){
14797 fn.call(scope || window, k, e);
14803 if(this.stopEvent){
14806 fn.call(scope || window, k, e);
14811 this.bindings.push(handler);
14815 * Shorthand for adding a single key listener
14816 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14817 * following options:
14818 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14819 * @param {Function} fn The function to call
14820 * @param {Object} scope (optional) The scope of the function
14822 on : function(key, fn, scope){
14823 var keyCode, shift, ctrl, alt;
14824 if(typeof key == "object" && !(key instanceof Array)){
14843 handleKeyDown : function(e){
14844 if(this.enabled){ //just in case
14845 var b = this.bindings;
14846 for(var i = 0, len = b.length; i < len; i++){
14847 b[i].call(this, e);
14853 * Returns true if this KeyMap is enabled
14854 * @return {Boolean}
14856 isEnabled : function(){
14857 return this.enabled;
14861 * Enables this KeyMap
14863 enable: function(){
14865 this.el.on(this.eventName, this.handleKeyDown, this);
14866 this.enabled = true;
14871 * Disable this KeyMap
14873 disable: function(){
14875 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14876 this.enabled = false;
14881 * Ext JS Library 1.1.1
14882 * Copyright(c) 2006-2007, Ext JS, LLC.
14884 * Originally Released Under LGPL - original licence link has changed is not relivant.
14887 * <script type="text/javascript">
14892 * @class Roo.util.TextMetrics
14893 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14894 * wide, in pixels, a given block of text will be.
14897 Roo.util.TextMetrics = function(){
14901 * Measures the size of the specified text
14902 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14903 * that can affect the size of the rendered text
14904 * @param {String} text The text to measure
14905 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14906 * in order to accurately measure the text height
14907 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14909 measure : function(el, text, fixedWidth){
14911 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14914 shared.setFixedWidth(fixedWidth || 'auto');
14915 return shared.getSize(text);
14919 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14920 * the overhead of multiple calls to initialize the style properties on each measurement.
14921 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14922 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14923 * in order to accurately measure the text height
14924 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14926 createInstance : function(el, fixedWidth){
14927 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14934 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14935 var ml = new Roo.Element(document.createElement('div'));
14936 document.body.appendChild(ml.dom);
14937 ml.position('absolute');
14938 ml.setLeftTop(-1000, -1000);
14942 ml.setWidth(fixedWidth);
14947 * Returns the size of the specified text based on the internal element's style and width properties
14948 * @memberOf Roo.util.TextMetrics.Instance#
14949 * @param {String} text The text to measure
14950 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14952 getSize : function(text){
14954 var s = ml.getSize();
14960 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14961 * that can affect the size of the rendered text
14962 * @memberOf Roo.util.TextMetrics.Instance#
14963 * @param {String/HTMLElement} el The element, dom node or id
14965 bind : function(el){
14967 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14972 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14973 * to set a fixed width in order to accurately measure the text height.
14974 * @memberOf Roo.util.TextMetrics.Instance#
14975 * @param {Number} width The width to set on the element
14977 setFixedWidth : function(width){
14978 ml.setWidth(width);
14982 * Returns the measured width of the specified text
14983 * @memberOf Roo.util.TextMetrics.Instance#
14984 * @param {String} text The text to measure
14985 * @return {Number} width The width in pixels
14987 getWidth : function(text){
14988 ml.dom.style.width = 'auto';
14989 return this.getSize(text).width;
14993 * Returns the measured height of the specified text. For multiline text, be sure to call
14994 * {@link #setFixedWidth} if necessary.
14995 * @memberOf Roo.util.TextMetrics.Instance#
14996 * @param {String} text The text to measure
14997 * @return {Number} height The height in pixels
14999 getHeight : function(text){
15000 return this.getSize(text).height;
15004 instance.bind(bindTo);
15009 // backwards compat
15010 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15012 * Ext JS Library 1.1.1
15013 * Copyright(c) 2006-2007, Ext JS, LLC.
15015 * Originally Released Under LGPL - original licence link has changed is not relivant.
15018 * <script type="text/javascript">
15022 * @class Roo.state.Provider
15023 * Abstract base class for state provider implementations. This class provides methods
15024 * for encoding and decoding <b>typed</b> variables including dates and defines the
15025 * Provider interface.
15027 Roo.state.Provider = function(){
15029 * @event statechange
15030 * Fires when a state change occurs.
15031 * @param {Provider} this This state provider
15032 * @param {String} key The state key which was changed
15033 * @param {String} value The encoded value for the state
15036 "statechange": true
15039 Roo.state.Provider.superclass.constructor.call(this);
15041 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15043 * Returns the current value for a key
15044 * @param {String} name The key name
15045 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15046 * @return {Mixed} The state data
15048 get : function(name, defaultValue){
15049 return typeof this.state[name] == "undefined" ?
15050 defaultValue : this.state[name];
15054 * Clears a value from the state
15055 * @param {String} name The key name
15057 clear : function(name){
15058 delete this.state[name];
15059 this.fireEvent("statechange", this, name, null);
15063 * Sets the value for a key
15064 * @param {String} name The key name
15065 * @param {Mixed} value The value to set
15067 set : function(name, value){
15068 this.state[name] = value;
15069 this.fireEvent("statechange", this, name, value);
15073 * Decodes a string previously encoded with {@link #encodeValue}.
15074 * @param {String} value The value to decode
15075 * @return {Mixed} The decoded value
15077 decodeValue : function(cookie){
15078 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15079 var matches = re.exec(unescape(cookie));
15080 if(!matches || !matches[1]) {
15081 return; // non state cookie
15083 var type = matches[1];
15084 var v = matches[2];
15087 return parseFloat(v);
15089 return new Date(Date.parse(v));
15094 var values = v.split("^");
15095 for(var i = 0, len = values.length; i < len; i++){
15096 all.push(this.decodeValue(values[i]));
15101 var values = v.split("^");
15102 for(var i = 0, len = values.length; i < len; i++){
15103 var kv = values[i].split("=");
15104 all[kv[0]] = this.decodeValue(kv[1]);
15113 * Encodes a value including type information. Decode with {@link #decodeValue}.
15114 * @param {Mixed} value The value to encode
15115 * @return {String} The encoded value
15117 encodeValue : function(v){
15119 if(typeof v == "number"){
15121 }else if(typeof v == "boolean"){
15122 enc = "b:" + (v ? "1" : "0");
15123 }else if(v instanceof Date){
15124 enc = "d:" + v.toGMTString();
15125 }else if(v instanceof Array){
15127 for(var i = 0, len = v.length; i < len; i++){
15128 flat += this.encodeValue(v[i]);
15134 }else if(typeof v == "object"){
15137 if(typeof v[key] != "function"){
15138 flat += key + "=" + this.encodeValue(v[key]) + "^";
15141 enc = "o:" + flat.substring(0, flat.length-1);
15145 return escape(enc);
15151 * Ext JS Library 1.1.1
15152 * Copyright(c) 2006-2007, Ext JS, LLC.
15154 * Originally Released Under LGPL - original licence link has changed is not relivant.
15157 * <script type="text/javascript">
15160 * @class Roo.state.Manager
15161 * This is the global state manager. By default all components that are "state aware" check this class
15162 * for state information if you don't pass them a custom state provider. In order for this class
15163 * to be useful, it must be initialized with a provider when your application initializes.
15165 // in your initialization function
15167 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15169 // supposed you have a {@link Roo.BorderLayout}
15170 var layout = new Roo.BorderLayout(...);
15171 layout.restoreState();
15172 // or a {Roo.BasicDialog}
15173 var dialog = new Roo.BasicDialog(...);
15174 dialog.restoreState();
15178 Roo.state.Manager = function(){
15179 var provider = new Roo.state.Provider();
15183 * Configures the default state provider for your application
15184 * @param {Provider} stateProvider The state provider to set
15186 setProvider : function(stateProvider){
15187 provider = stateProvider;
15191 * Returns the current value for a key
15192 * @param {String} name The key name
15193 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15194 * @return {Mixed} The state data
15196 get : function(key, defaultValue){
15197 return provider.get(key, defaultValue);
15201 * Sets the value for a key
15202 * @param {String} name The key name
15203 * @param {Mixed} value The state data
15205 set : function(key, value){
15206 provider.set(key, value);
15210 * Clears a value from the state
15211 * @param {String} name The key name
15213 clear : function(key){
15214 provider.clear(key);
15218 * Gets the currently configured state provider
15219 * @return {Provider} The state provider
15221 getProvider : function(){
15228 * Ext JS Library 1.1.1
15229 * Copyright(c) 2006-2007, Ext JS, LLC.
15231 * Originally Released Under LGPL - original licence link has changed is not relivant.
15234 * <script type="text/javascript">
15237 * @class Roo.state.CookieProvider
15238 * @extends Roo.state.Provider
15239 * The default Provider implementation which saves state via cookies.
15242 var cp = new Roo.state.CookieProvider({
15244 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15245 domain: "roojs.com"
15247 Roo.state.Manager.setProvider(cp);
15249 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15250 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15251 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15252 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15253 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15254 * domain the page is running on including the 'www' like 'www.roojs.com')
15255 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15257 * Create a new CookieProvider
15258 * @param {Object} config The configuration object
15260 Roo.state.CookieProvider = function(config){
15261 Roo.state.CookieProvider.superclass.constructor.call(this);
15263 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15264 this.domain = null;
15265 this.secure = false;
15266 Roo.apply(this, config);
15267 this.state = this.readCookies();
15270 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15272 set : function(name, value){
15273 if(typeof value == "undefined" || value === null){
15277 this.setCookie(name, value);
15278 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15282 clear : function(name){
15283 this.clearCookie(name);
15284 Roo.state.CookieProvider.superclass.clear.call(this, name);
15288 readCookies : function(){
15290 var c = document.cookie + ";";
15291 var re = /\s?(.*?)=(.*?);/g;
15293 while((matches = re.exec(c)) != null){
15294 var name = matches[1];
15295 var value = matches[2];
15296 if(name && name.substring(0,3) == "ys-"){
15297 cookies[name.substr(3)] = this.decodeValue(value);
15304 setCookie : function(name, value){
15305 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15306 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15307 ((this.path == null) ? "" : ("; path=" + this.path)) +
15308 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15309 ((this.secure == true) ? "; secure" : "");
15313 clearCookie : function(name){
15314 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15315 ((this.path == null) ? "" : ("; path=" + this.path)) +
15316 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15317 ((this.secure == true) ? "; secure" : "");
15321 * Ext JS Library 1.1.1
15322 * Copyright(c) 2006-2007, Ext JS, LLC.
15324 * Originally Released Under LGPL - original licence link has changed is not relivant.
15327 * <script type="text/javascript">
15332 * @class Roo.ComponentMgr
15333 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15336 Roo.ComponentMgr = function(){
15337 var all = new Roo.util.MixedCollection();
15341 * Registers a component.
15342 * @param {Roo.Component} c The component
15344 register : function(c){
15349 * Unregisters a component.
15350 * @param {Roo.Component} c The component
15352 unregister : function(c){
15357 * Returns a component by id
15358 * @param {String} id The component id
15360 get : function(id){
15361 return all.get(id);
15365 * Registers a function that will be called when a specified component is added to ComponentMgr
15366 * @param {String} id The component id
15367 * @param {Funtction} fn The callback function
15368 * @param {Object} scope The scope of the callback
15370 onAvailable : function(id, fn, scope){
15371 all.on("add", function(index, o){
15373 fn.call(scope || o, o);
15374 all.un("add", fn, scope);
15381 * Ext JS Library 1.1.1
15382 * Copyright(c) 2006-2007, Ext JS, LLC.
15384 * Originally Released Under LGPL - original licence link has changed is not relivant.
15387 * <script type="text/javascript">
15391 * @class Roo.Component
15392 * @extends Roo.util.Observable
15393 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15394 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15395 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15396 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15397 * All visual components (widgets) that require rendering into a layout should subclass Component.
15399 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15400 * 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
15401 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15403 Roo.Component = function(config){
15404 config = config || {};
15405 if(config.tagName || config.dom || typeof config == "string"){ // element object
15406 config = {el: config, id: config.id || config};
15408 this.initialConfig = config;
15410 Roo.apply(this, config);
15414 * Fires after the component is disabled.
15415 * @param {Roo.Component} this
15420 * Fires after the component is enabled.
15421 * @param {Roo.Component} this
15425 * @event beforeshow
15426 * Fires before the component is shown. Return false to stop the show.
15427 * @param {Roo.Component} this
15432 * Fires after the component is shown.
15433 * @param {Roo.Component} this
15437 * @event beforehide
15438 * Fires before the component is hidden. Return false to stop the hide.
15439 * @param {Roo.Component} this
15444 * Fires after the component is hidden.
15445 * @param {Roo.Component} this
15449 * @event beforerender
15450 * Fires before the component is rendered. Return false to stop the render.
15451 * @param {Roo.Component} this
15453 beforerender : true,
15456 * Fires after the component is rendered.
15457 * @param {Roo.Component} this
15461 * @event beforedestroy
15462 * Fires before the component is destroyed. Return false to stop the destroy.
15463 * @param {Roo.Component} this
15465 beforedestroy : true,
15468 * Fires after the component is destroyed.
15469 * @param {Roo.Component} this
15474 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15476 Roo.ComponentMgr.register(this);
15477 Roo.Component.superclass.constructor.call(this);
15478 this.initComponent();
15479 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15480 this.render(this.renderTo);
15481 delete this.renderTo;
15486 Roo.Component.AUTO_ID = 1000;
15488 Roo.extend(Roo.Component, Roo.util.Observable, {
15490 * @scope Roo.Component.prototype
15492 * true if this component is hidden. Read-only.
15497 * true if this component is disabled. Read-only.
15502 * true if this component has been rendered. Read-only.
15506 /** @cfg {String} disableClass
15507 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15509 disabledClass : "x-item-disabled",
15510 /** @cfg {Boolean} allowDomMove
15511 * Whether the component can move the Dom node when rendering (defaults to true).
15513 allowDomMove : true,
15514 /** @cfg {String} hideMode (display|visibility)
15515 * How this component should hidden. Supported values are
15516 * "visibility" (css visibility), "offsets" (negative offset position) and
15517 * "display" (css display) - defaults to "display".
15519 hideMode: 'display',
15522 ctype : "Roo.Component",
15525 * @cfg {String} actionMode
15526 * which property holds the element that used for hide() / show() / disable() / enable()
15527 * default is 'el' for forms you probably want to set this to fieldEl
15532 getActionEl : function(){
15533 return this[this.actionMode];
15536 initComponent : Roo.emptyFn,
15538 * If this is a lazy rendering component, render it to its container element.
15539 * @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.
15541 render : function(container, position){
15547 if(this.fireEvent("beforerender", this) === false){
15551 if(!container && this.el){
15552 this.el = Roo.get(this.el);
15553 container = this.el.dom.parentNode;
15554 this.allowDomMove = false;
15556 this.container = Roo.get(container);
15557 this.rendered = true;
15558 if(position !== undefined){
15559 if(typeof position == 'number'){
15560 position = this.container.dom.childNodes[position];
15562 position = Roo.getDom(position);
15565 this.onRender(this.container, position || null);
15567 this.el.addClass(this.cls);
15571 this.el.applyStyles(this.style);
15574 this.fireEvent("render", this);
15575 this.afterRender(this.container);
15588 // default function is not really useful
15589 onRender : function(ct, position){
15591 this.el = Roo.get(this.el);
15592 if(this.allowDomMove !== false){
15593 ct.dom.insertBefore(this.el.dom, position);
15599 getAutoCreate : function(){
15600 var cfg = typeof this.autoCreate == "object" ?
15601 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15602 if(this.id && !cfg.id){
15609 afterRender : Roo.emptyFn,
15612 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15613 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15615 destroy : function(){
15616 if(this.fireEvent("beforedestroy", this) !== false){
15617 this.purgeListeners();
15618 this.beforeDestroy();
15620 this.el.removeAllListeners();
15622 if(this.actionMode == "container"){
15623 this.container.remove();
15627 Roo.ComponentMgr.unregister(this);
15628 this.fireEvent("destroy", this);
15633 beforeDestroy : function(){
15638 onDestroy : function(){
15643 * Returns the underlying {@link Roo.Element}.
15644 * @return {Roo.Element} The element
15646 getEl : function(){
15651 * Returns the id of this component.
15654 getId : function(){
15659 * Try to focus this component.
15660 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15661 * @return {Roo.Component} this
15663 focus : function(selectText){
15666 if(selectText === true){
15667 this.el.dom.select();
15682 * Disable this component.
15683 * @return {Roo.Component} this
15685 disable : function(){
15689 this.disabled = true;
15690 this.fireEvent("disable", this);
15695 onDisable : function(){
15696 this.getActionEl().addClass(this.disabledClass);
15697 this.el.dom.disabled = true;
15701 * Enable this component.
15702 * @return {Roo.Component} this
15704 enable : function(){
15708 this.disabled = false;
15709 this.fireEvent("enable", this);
15714 onEnable : function(){
15715 this.getActionEl().removeClass(this.disabledClass);
15716 this.el.dom.disabled = false;
15720 * Convenience function for setting disabled/enabled by boolean.
15721 * @param {Boolean} disabled
15723 setDisabled : function(disabled){
15724 this[disabled ? "disable" : "enable"]();
15728 * Show this component.
15729 * @return {Roo.Component} this
15732 if(this.fireEvent("beforeshow", this) !== false){
15733 this.hidden = false;
15737 this.fireEvent("show", this);
15743 onShow : function(){
15744 var ae = this.getActionEl();
15745 if(this.hideMode == 'visibility'){
15746 ae.dom.style.visibility = "visible";
15747 }else if(this.hideMode == 'offsets'){
15748 ae.removeClass('x-hidden');
15750 ae.dom.style.display = "";
15755 * Hide this component.
15756 * @return {Roo.Component} this
15759 if(this.fireEvent("beforehide", this) !== false){
15760 this.hidden = true;
15764 this.fireEvent("hide", this);
15770 onHide : function(){
15771 var ae = this.getActionEl();
15772 if(this.hideMode == 'visibility'){
15773 ae.dom.style.visibility = "hidden";
15774 }else if(this.hideMode == 'offsets'){
15775 ae.addClass('x-hidden');
15777 ae.dom.style.display = "none";
15782 * Convenience function to hide or show this component by boolean.
15783 * @param {Boolean} visible True to show, false to hide
15784 * @return {Roo.Component} this
15786 setVisible: function(visible){
15796 * Returns true if this component is visible.
15798 isVisible : function(){
15799 return this.getActionEl().isVisible();
15802 cloneConfig : function(overrides){
15803 overrides = overrides || {};
15804 var id = overrides.id || Roo.id();
15805 var cfg = Roo.applyIf(overrides, this.initialConfig);
15806 cfg.id = id; // prevent dup id
15807 return new this.constructor(cfg);
15811 * Ext JS Library 1.1.1
15812 * Copyright(c) 2006-2007, Ext JS, LLC.
15814 * Originally Released Under LGPL - original licence link has changed is not relivant.
15817 * <script type="text/javascript">
15821 * @class Roo.BoxComponent
15822 * @extends Roo.Component
15823 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15824 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15825 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15826 * layout containers.
15828 * @param {Roo.Element/String/Object} config The configuration options.
15830 Roo.BoxComponent = function(config){
15831 Roo.Component.call(this, config);
15835 * Fires after the component is resized.
15836 * @param {Roo.Component} this
15837 * @param {Number} adjWidth The box-adjusted width that was set
15838 * @param {Number} adjHeight The box-adjusted height that was set
15839 * @param {Number} rawWidth The width that was originally specified
15840 * @param {Number} rawHeight The height that was originally specified
15845 * Fires after the component is moved.
15846 * @param {Roo.Component} this
15847 * @param {Number} x The new x position
15848 * @param {Number} y The new y position
15854 Roo.extend(Roo.BoxComponent, Roo.Component, {
15855 // private, set in afterRender to signify that the component has been rendered
15857 // private, used to defer height settings to subclasses
15858 deferHeight: false,
15859 /** @cfg {Number} width
15860 * width (optional) size of component
15862 /** @cfg {Number} height
15863 * height (optional) size of component
15867 * Sets the width and height of the component. This method fires the resize event. This method can accept
15868 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15869 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15870 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15871 * @return {Roo.BoxComponent} this
15873 setSize : function(w, h){
15874 // support for standard size objects
15875 if(typeof w == 'object'){
15880 if(!this.boxReady){
15886 // prevent recalcs when not needed
15887 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15890 this.lastSize = {width: w, height: h};
15892 var adj = this.adjustSize(w, h);
15893 var aw = adj.width, ah = adj.height;
15894 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15895 var rz = this.getResizeEl();
15896 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15897 rz.setSize(aw, ah);
15898 }else if(!this.deferHeight && ah !== undefined){
15900 }else if(aw !== undefined){
15903 this.onResize(aw, ah, w, h);
15904 this.fireEvent('resize', this, aw, ah, w, h);
15910 * Gets the current size of the component's underlying element.
15911 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15913 getSize : function(){
15914 return this.el.getSize();
15918 * Gets the current XY position of the component's underlying element.
15919 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15920 * @return {Array} The XY position of the element (e.g., [100, 200])
15922 getPosition : function(local){
15923 if(local === true){
15924 return [this.el.getLeft(true), this.el.getTop(true)];
15926 return this.xy || this.el.getXY();
15930 * Gets the current box measurements of the component's underlying element.
15931 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15932 * @returns {Object} box An object in the format {x, y, width, height}
15934 getBox : function(local){
15935 var s = this.el.getSize();
15937 s.x = this.el.getLeft(true);
15938 s.y = this.el.getTop(true);
15940 var xy = this.xy || this.el.getXY();
15948 * Sets the current box measurements of the component's underlying element.
15949 * @param {Object} box An object in the format {x, y, width, height}
15950 * @returns {Roo.BoxComponent} this
15952 updateBox : function(box){
15953 this.setSize(box.width, box.height);
15954 this.setPagePosition(box.x, box.y);
15959 getResizeEl : function(){
15960 return this.resizeEl || this.el;
15964 getPositionEl : function(){
15965 return this.positionEl || this.el;
15969 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15970 * This method fires the move event.
15971 * @param {Number} left The new left
15972 * @param {Number} top The new top
15973 * @returns {Roo.BoxComponent} this
15975 setPosition : function(x, y){
15978 if(!this.boxReady){
15981 var adj = this.adjustPosition(x, y);
15982 var ax = adj.x, ay = adj.y;
15984 var el = this.getPositionEl();
15985 if(ax !== undefined || ay !== undefined){
15986 if(ax !== undefined && ay !== undefined){
15987 el.setLeftTop(ax, ay);
15988 }else if(ax !== undefined){
15990 }else if(ay !== undefined){
15993 this.onPosition(ax, ay);
15994 this.fireEvent('move', this, ax, ay);
16000 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16001 * This method fires the move event.
16002 * @param {Number} x The new x position
16003 * @param {Number} y The new y position
16004 * @returns {Roo.BoxComponent} this
16006 setPagePosition : function(x, y){
16009 if(!this.boxReady){
16012 if(x === undefined || y === undefined){ // cannot translate undefined points
16015 var p = this.el.translatePoints(x, y);
16016 this.setPosition(p.left, p.top);
16021 onRender : function(ct, position){
16022 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16024 this.resizeEl = Roo.get(this.resizeEl);
16026 if(this.positionEl){
16027 this.positionEl = Roo.get(this.positionEl);
16032 afterRender : function(){
16033 Roo.BoxComponent.superclass.afterRender.call(this);
16034 this.boxReady = true;
16035 this.setSize(this.width, this.height);
16036 if(this.x || this.y){
16037 this.setPosition(this.x, this.y);
16039 if(this.pageX || this.pageY){
16040 this.setPagePosition(this.pageX, this.pageY);
16045 * Force the component's size to recalculate based on the underlying element's current height and width.
16046 * @returns {Roo.BoxComponent} this
16048 syncSize : function(){
16049 delete this.lastSize;
16050 this.setSize(this.el.getWidth(), this.el.getHeight());
16055 * Called after the component is resized, this method is empty by default but can be implemented by any
16056 * subclass that needs to perform custom logic after a resize occurs.
16057 * @param {Number} adjWidth The box-adjusted width that was set
16058 * @param {Number} adjHeight The box-adjusted height that was set
16059 * @param {Number} rawWidth The width that was originally specified
16060 * @param {Number} rawHeight The height that was originally specified
16062 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16067 * Called after the component is moved, this method is empty by default but can be implemented by any
16068 * subclass that needs to perform custom logic after a move occurs.
16069 * @param {Number} x The new x position
16070 * @param {Number} y The new y position
16072 onPosition : function(x, y){
16077 adjustSize : function(w, h){
16078 if(this.autoWidth){
16081 if(this.autoHeight){
16084 return {width : w, height: h};
16088 adjustPosition : function(x, y){
16089 return {x : x, y: y};
16093 * Ext JS Library 1.1.1
16094 * Copyright(c) 2006-2007, Ext JS, LLC.
16096 * Originally Released Under LGPL - original licence link has changed is not relivant.
16099 * <script type="text/javascript">
16104 * @extends Roo.Element
16105 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16106 * automatic maintaining of shadow/shim positions.
16107 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16108 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16109 * you can pass a string with a CSS class name. False turns off the shadow.
16110 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16111 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16112 * @cfg {String} cls CSS class to add to the element
16113 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16114 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16116 * @param {Object} config An object with config options.
16117 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16120 Roo.Layer = function(config, existingEl){
16121 config = config || {};
16122 var dh = Roo.DomHelper;
16123 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16125 this.dom = Roo.getDom(existingEl);
16128 var o = config.dh || {tag: "div", cls: "x-layer"};
16129 this.dom = dh.append(pel, o);
16132 this.addClass(config.cls);
16134 this.constrain = config.constrain !== false;
16135 this.visibilityMode = Roo.Element.VISIBILITY;
16137 this.id = this.dom.id = config.id;
16139 this.id = Roo.id(this.dom);
16141 this.zindex = config.zindex || this.getZIndex();
16142 this.position("absolute", this.zindex);
16144 this.shadowOffset = config.shadowOffset || 4;
16145 this.shadow = new Roo.Shadow({
16146 offset : this.shadowOffset,
16147 mode : config.shadow
16150 this.shadowOffset = 0;
16152 this.useShim = config.shim !== false && Roo.useShims;
16153 this.useDisplay = config.useDisplay;
16157 var supr = Roo.Element.prototype;
16159 // shims are shared among layer to keep from having 100 iframes
16162 Roo.extend(Roo.Layer, Roo.Element, {
16164 getZIndex : function(){
16165 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16168 getShim : function(){
16175 var shim = shims.shift();
16177 shim = this.createShim();
16178 shim.enableDisplayMode('block');
16179 shim.dom.style.display = 'none';
16180 shim.dom.style.visibility = 'visible';
16182 var pn = this.dom.parentNode;
16183 if(shim.dom.parentNode != pn){
16184 pn.insertBefore(shim.dom, this.dom);
16186 shim.setStyle('z-index', this.getZIndex()-2);
16191 hideShim : function(){
16193 this.shim.setDisplayed(false);
16194 shims.push(this.shim);
16199 disableShadow : function(){
16201 this.shadowDisabled = true;
16202 this.shadow.hide();
16203 this.lastShadowOffset = this.shadowOffset;
16204 this.shadowOffset = 0;
16208 enableShadow : function(show){
16210 this.shadowDisabled = false;
16211 this.shadowOffset = this.lastShadowOffset;
16212 delete this.lastShadowOffset;
16220 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16221 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16222 sync : function(doShow){
16223 var sw = this.shadow;
16224 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16225 var sh = this.getShim();
16227 var w = this.getWidth(),
16228 h = this.getHeight();
16230 var l = this.getLeft(true),
16231 t = this.getTop(true);
16233 if(sw && !this.shadowDisabled){
16234 if(doShow && !sw.isVisible()){
16237 sw.realign(l, t, w, h);
16243 // fit the shim behind the shadow, so it is shimmed too
16244 var a = sw.adjusts, s = sh.dom.style;
16245 s.left = (Math.min(l, l+a.l))+"px";
16246 s.top = (Math.min(t, t+a.t))+"px";
16247 s.width = (w+a.w)+"px";
16248 s.height = (h+a.h)+"px";
16255 sh.setLeftTop(l, t);
16262 destroy : function(){
16265 this.shadow.hide();
16267 this.removeAllListeners();
16268 var pn = this.dom.parentNode;
16270 pn.removeChild(this.dom);
16272 Roo.Element.uncache(this.id);
16275 remove : function(){
16280 beginUpdate : function(){
16281 this.updating = true;
16285 endUpdate : function(){
16286 this.updating = false;
16291 hideUnders : function(negOffset){
16293 this.shadow.hide();
16299 constrainXY : function(){
16300 if(this.constrain){
16301 var vw = Roo.lib.Dom.getViewWidth(),
16302 vh = Roo.lib.Dom.getViewHeight();
16303 var s = Roo.get(document).getScroll();
16305 var xy = this.getXY();
16306 var x = xy[0], y = xy[1];
16307 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16308 // only move it if it needs it
16310 // first validate right/bottom
16311 if((x + w) > vw+s.left){
16312 x = vw - w - this.shadowOffset;
16315 if((y + h) > vh+s.top){
16316 y = vh - h - this.shadowOffset;
16319 // then make sure top/left isn't negative
16330 var ay = this.avoidY;
16331 if(y <= ay && (y+h) >= ay){
16337 supr.setXY.call(this, xy);
16343 isVisible : function(){
16344 return this.visible;
16348 showAction : function(){
16349 this.visible = true; // track visibility to prevent getStyle calls
16350 if(this.useDisplay === true){
16351 this.setDisplayed("");
16352 }else if(this.lastXY){
16353 supr.setXY.call(this, this.lastXY);
16354 }else if(this.lastLT){
16355 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16360 hideAction : function(){
16361 this.visible = false;
16362 if(this.useDisplay === true){
16363 this.setDisplayed(false);
16365 this.setLeftTop(-10000,-10000);
16369 // overridden Element method
16370 setVisible : function(v, a, d, c, e){
16375 var cb = function(){
16380 }.createDelegate(this);
16381 supr.setVisible.call(this, true, true, d, cb, e);
16384 this.hideUnders(true);
16393 }.createDelegate(this);
16395 supr.setVisible.call(this, v, a, d, cb, e);
16404 storeXY : function(xy){
16405 delete this.lastLT;
16409 storeLeftTop : function(left, top){
16410 delete this.lastXY;
16411 this.lastLT = [left, top];
16415 beforeFx : function(){
16416 this.beforeAction();
16417 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16421 afterFx : function(){
16422 Roo.Layer.superclass.afterFx.apply(this, arguments);
16423 this.sync(this.isVisible());
16427 beforeAction : function(){
16428 if(!this.updating && this.shadow){
16429 this.shadow.hide();
16433 // overridden Element method
16434 setLeft : function(left){
16435 this.storeLeftTop(left, this.getTop(true));
16436 supr.setLeft.apply(this, arguments);
16440 setTop : function(top){
16441 this.storeLeftTop(this.getLeft(true), top);
16442 supr.setTop.apply(this, arguments);
16446 setLeftTop : function(left, top){
16447 this.storeLeftTop(left, top);
16448 supr.setLeftTop.apply(this, arguments);
16452 setXY : function(xy, a, d, c, e){
16454 this.beforeAction();
16456 var cb = this.createCB(c);
16457 supr.setXY.call(this, xy, a, d, cb, e);
16464 createCB : function(c){
16475 // overridden Element method
16476 setX : function(x, a, d, c, e){
16477 this.setXY([x, this.getY()], a, d, c, e);
16480 // overridden Element method
16481 setY : function(y, a, d, c, e){
16482 this.setXY([this.getX(), y], a, d, c, e);
16485 // overridden Element method
16486 setSize : function(w, h, a, d, c, e){
16487 this.beforeAction();
16488 var cb = this.createCB(c);
16489 supr.setSize.call(this, w, h, a, d, cb, e);
16495 // overridden Element method
16496 setWidth : function(w, a, d, c, e){
16497 this.beforeAction();
16498 var cb = this.createCB(c);
16499 supr.setWidth.call(this, w, a, d, cb, e);
16505 // overridden Element method
16506 setHeight : function(h, a, d, c, e){
16507 this.beforeAction();
16508 var cb = this.createCB(c);
16509 supr.setHeight.call(this, h, a, d, cb, e);
16515 // overridden Element method
16516 setBounds : function(x, y, w, h, a, d, c, e){
16517 this.beforeAction();
16518 var cb = this.createCB(c);
16520 this.storeXY([x, y]);
16521 supr.setXY.call(this, [x, y]);
16522 supr.setSize.call(this, w, h, a, d, cb, e);
16525 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16531 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16532 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16533 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16534 * @param {Number} zindex The new z-index to set
16535 * @return {this} The Layer
16537 setZIndex : function(zindex){
16538 this.zindex = zindex;
16539 this.setStyle("z-index", zindex + 2);
16541 this.shadow.setZIndex(zindex + 1);
16544 this.shim.setStyle("z-index", zindex);
16549 * Original code for Roojs - LGPL
16550 * <script type="text/javascript">
16554 * @class Roo.XComponent
16555 * A delayed Element creator...
16556 * Or a way to group chunks of interface together.
16557 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16558 * used in conjunction with XComponent.build() it will create an instance of each element,
16559 * then call addxtype() to build the User interface.
16561 * Mypart.xyx = new Roo.XComponent({
16563 parent : 'Mypart.xyz', // empty == document.element.!!
16567 disabled : function() {}
16569 tree : function() { // return an tree of xtype declared components
16573 xtype : 'NestedLayoutPanel',
16580 * It can be used to build a big heiracy, with parent etc.
16581 * or you can just use this to render a single compoent to a dom element
16582 * MYPART.render(Roo.Element | String(id) | dom_element )
16589 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16590 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16592 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16594 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16595 * - if mulitple topModules exist, the last one is defined as the top module.
16599 * When the top level or multiple modules are to embedded into a existing HTML page,
16600 * the parent element can container '#id' of the element where the module will be drawn.
16604 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16605 * it relies more on a include mechanism, where sub modules are included into an outer page.
16606 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16608 * Bootstrap Roo Included elements
16610 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16611 * hence confusing the component builder as it thinks there are multiple top level elements.
16613 * String Over-ride & Translations
16615 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16616 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16617 * are needed. @see Roo.XComponent.overlayString
16621 * @extends Roo.util.Observable
16623 * @param cfg {Object} configuration of component
16626 Roo.XComponent = function(cfg) {
16627 Roo.apply(this, cfg);
16631 * Fires when this the componnt is built
16632 * @param {Roo.XComponent} c the component
16637 this.region = this.region || 'center'; // default..
16638 Roo.XComponent.register(this);
16639 this.modules = false;
16640 this.el = false; // where the layout goes..
16644 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16647 * The created element (with Roo.factory())
16648 * @type {Roo.Layout}
16654 * for BC - use el in new code
16655 * @type {Roo.Layout}
16661 * for BC - use el in new code
16662 * @type {Roo.Layout}
16667 * @cfg {Function|boolean} disabled
16668 * If this module is disabled by some rule, return true from the funtion
16673 * @cfg {String} parent
16674 * Name of parent element which it get xtype added to..
16679 * @cfg {String} order
16680 * Used to set the order in which elements are created (usefull for multiple tabs)
16685 * @cfg {String} name
16686 * String to display while loading.
16690 * @cfg {String} region
16691 * Region to render component to (defaults to center)
16696 * @cfg {Array} items
16697 * A single item array - the first element is the root of the tree..
16698 * It's done this way to stay compatible with the Xtype system...
16704 * The method that retuns the tree of parts that make up this compoennt
16711 * render element to dom or tree
16712 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16715 render : function(el)
16719 var hp = this.parent ? 1 : 0;
16720 Roo.debug && Roo.log(this);
16722 var tree = this._tree ? this._tree() : this.tree();
16725 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16726 // if parent is a '#.....' string, then let's use that..
16727 var ename = this.parent.substr(1);
16728 this.parent = false;
16729 Roo.debug && Roo.log(ename);
16731 case 'bootstrap-body':
16732 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16733 // this is the BorderLayout standard?
16734 this.parent = { el : true };
16737 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16738 // need to insert stuff...
16740 el : new Roo.bootstrap.layout.Border({
16741 el : document.body,
16747 tabPosition: 'top',
16748 //resizeTabs: true,
16749 alwaysShowTabs: true,
16759 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16760 this.parent = { el : new Roo.bootstrap.Body() };
16761 Roo.debug && Roo.log("setting el to doc body");
16764 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16768 this.parent = { el : true};
16771 el = Roo.get(ename);
16772 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16773 this.parent = { el : true};
16780 if (!el && !this.parent) {
16781 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16786 Roo.debug && Roo.log("EL:");
16787 Roo.debug && Roo.log(el);
16788 Roo.debug && Roo.log("this.parent.el:");
16789 Roo.debug && Roo.log(this.parent.el);
16792 // altertive root elements ??? - we need a better way to indicate these.
16793 var is_alt = Roo.XComponent.is_alt ||
16794 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16795 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16796 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16800 if (!this.parent && is_alt) {
16801 //el = Roo.get(document.body);
16802 this.parent = { el : true };
16807 if (!this.parent) {
16809 Roo.debug && Roo.log("no parent - creating one");
16811 el = el ? Roo.get(el) : false;
16813 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16816 el : new Roo.bootstrap.layout.Border({
16817 el: el || document.body,
16823 tabPosition: 'top',
16824 //resizeTabs: true,
16825 alwaysShowTabs: false,
16828 overflow: 'visible'
16834 // it's a top level one..
16836 el : new Roo.BorderLayout(el || document.body, {
16841 tabPosition: 'top',
16842 //resizeTabs: true,
16843 alwaysShowTabs: el && hp? false : true,
16844 hideTabs: el || !hp ? true : false,
16852 if (!this.parent.el) {
16853 // probably an old style ctor, which has been disabled.
16857 // The 'tree' method is '_tree now'
16859 tree.region = tree.region || this.region;
16860 var is_body = false;
16861 if (this.parent.el === true) {
16862 // bootstrap... - body..
16866 this.parent.el = Roo.factory(tree);
16870 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16871 this.fireEvent('built', this);
16873 this.panel = this.el;
16874 this.layout = this.panel.layout;
16875 this.parentLayout = this.parent.layout || false;
16881 Roo.apply(Roo.XComponent, {
16883 * @property hideProgress
16884 * true to disable the building progress bar.. usefull on single page renders.
16887 hideProgress : false,
16889 * @property buildCompleted
16890 * True when the builder has completed building the interface.
16893 buildCompleted : false,
16896 * @property topModule
16897 * the upper most module - uses document.element as it's constructor.
16904 * @property modules
16905 * array of modules to be created by registration system.
16906 * @type {Array} of Roo.XComponent
16911 * @property elmodules
16912 * array of modules to be created by which use #ID
16913 * @type {Array} of Roo.XComponent
16920 * Is an alternative Root - normally used by bootstrap or other systems,
16921 * where the top element in the tree can wrap 'body'
16922 * @type {boolean} (default false)
16927 * @property build_from_html
16928 * Build elements from html - used by bootstrap HTML stuff
16929 * - this is cleared after build is completed
16930 * @type {boolean} (default false)
16933 build_from_html : false,
16935 * Register components to be built later.
16937 * This solves the following issues
16938 * - Building is not done on page load, but after an authentication process has occured.
16939 * - Interface elements are registered on page load
16940 * - Parent Interface elements may not be loaded before child, so this handles that..
16947 module : 'Pman.Tab.projectMgr',
16949 parent : 'Pman.layout',
16950 disabled : false, // or use a function..
16953 * * @param {Object} details about module
16955 register : function(obj) {
16957 Roo.XComponent.event.fireEvent('register', obj);
16958 switch(typeof(obj.disabled) ) {
16964 if ( obj.disabled() ) {
16970 if (obj.disabled || obj.region == '#disabled') {
16976 this.modules.push(obj);
16980 * convert a string to an object..
16981 * eg. 'AAA.BBB' -> finds AAA.BBB
16985 toObject : function(str)
16987 if (!str || typeof(str) == 'object') {
16990 if (str.substring(0,1) == '#') {
16994 var ar = str.split('.');
16999 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17001 throw "Module not found : " + str;
17005 throw "Module not found : " + str;
17007 Roo.each(ar, function(e) {
17008 if (typeof(o[e]) == 'undefined') {
17009 throw "Module not found : " + str;
17020 * move modules into their correct place in the tree..
17023 preBuild : function ()
17026 Roo.each(this.modules , function (obj)
17028 Roo.XComponent.event.fireEvent('beforebuild', obj);
17030 var opar = obj.parent;
17032 obj.parent = this.toObject(opar);
17034 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17039 Roo.debug && Roo.log("GOT top level module");
17040 Roo.debug && Roo.log(obj);
17041 obj.modules = new Roo.util.MixedCollection(false,
17042 function(o) { return o.order + '' }
17044 this.topModule = obj;
17047 // parent is a string (usually a dom element name..)
17048 if (typeof(obj.parent) == 'string') {
17049 this.elmodules.push(obj);
17052 if (obj.parent.constructor != Roo.XComponent) {
17053 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17055 if (!obj.parent.modules) {
17056 obj.parent.modules = new Roo.util.MixedCollection(false,
17057 function(o) { return o.order + '' }
17060 if (obj.parent.disabled) {
17061 obj.disabled = true;
17063 obj.parent.modules.add(obj);
17068 * make a list of modules to build.
17069 * @return {Array} list of modules.
17072 buildOrder : function()
17075 var cmp = function(a,b) {
17076 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17078 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17079 throw "No top level modules to build";
17082 // make a flat list in order of modules to build.
17083 var mods = this.topModule ? [ this.topModule ] : [];
17086 // elmodules (is a list of DOM based modules )
17087 Roo.each(this.elmodules, function(e) {
17089 if (!this.topModule &&
17090 typeof(e.parent) == 'string' &&
17091 e.parent.substring(0,1) == '#' &&
17092 Roo.get(e.parent.substr(1))
17095 _this.topModule = e;
17101 // add modules to their parents..
17102 var addMod = function(m) {
17103 Roo.debug && Roo.log("build Order: add: " + m.name);
17106 if (m.modules && !m.disabled) {
17107 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17108 m.modules.keySort('ASC', cmp );
17109 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17111 m.modules.each(addMod);
17113 Roo.debug && Roo.log("build Order: no child modules");
17115 // not sure if this is used any more..
17117 m.finalize.name = m.name + " (clean up) ";
17118 mods.push(m.finalize);
17122 if (this.topModule && this.topModule.modules) {
17123 this.topModule.modules.keySort('ASC', cmp );
17124 this.topModule.modules.each(addMod);
17130 * Build the registered modules.
17131 * @param {Object} parent element.
17132 * @param {Function} optional method to call after module has been added.
17136 build : function(opts)
17139 if (typeof(opts) != 'undefined') {
17140 Roo.apply(this,opts);
17144 var mods = this.buildOrder();
17146 //this.allmods = mods;
17147 //Roo.debug && Roo.log(mods);
17149 if (!mods.length) { // should not happen
17150 throw "NO modules!!!";
17154 var msg = "Building Interface...";
17155 // flash it up as modal - so we store the mask!?
17156 if (!this.hideProgress && Roo.MessageBox) {
17157 Roo.MessageBox.show({ title: 'loading' });
17158 Roo.MessageBox.show({
17159 title: "Please wait...",
17169 var total = mods.length;
17172 var progressRun = function() {
17173 if (!mods.length) {
17174 Roo.debug && Roo.log('hide?');
17175 if (!this.hideProgress && Roo.MessageBox) {
17176 Roo.MessageBox.hide();
17178 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17180 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17186 var m = mods.shift();
17189 Roo.debug && Roo.log(m);
17190 // not sure if this is supported any more.. - modules that are are just function
17191 if (typeof(m) == 'function') {
17193 return progressRun.defer(10, _this);
17197 msg = "Building Interface " + (total - mods.length) +
17199 (m.name ? (' - ' + m.name) : '');
17200 Roo.debug && Roo.log(msg);
17201 if (!_this.hideProgress && Roo.MessageBox) {
17202 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17206 // is the module disabled?
17207 var disabled = (typeof(m.disabled) == 'function') ?
17208 m.disabled.call(m.module.disabled) : m.disabled;
17212 return progressRun(); // we do not update the display!
17220 // it's 10 on top level, and 1 on others??? why...
17221 return progressRun.defer(10, _this);
17224 progressRun.defer(1, _this);
17230 * Overlay a set of modified strings onto a component
17231 * This is dependant on our builder exporting the strings and 'named strings' elements.
17233 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17234 * @param {Object} associative array of 'named' string and it's new value.
17237 overlayStrings : function( component, strings )
17239 if (typeof(component['_named_strings']) == 'undefined') {
17240 throw "ERROR: component does not have _named_strings";
17242 for ( var k in strings ) {
17243 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17244 if (md !== false) {
17245 component['_strings'][md] = strings[k];
17247 Roo.log('could not find named string: ' + k + ' in');
17248 Roo.log(component);
17263 * wrapper for event.on - aliased later..
17264 * Typically use to register a event handler for register:
17266 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17275 Roo.XComponent.event = new Roo.util.Observable({
17279 * Fires when an Component is registered,
17280 * set the disable property on the Component to stop registration.
17281 * @param {Roo.XComponent} c the component being registerd.
17286 * @event beforebuild
17287 * Fires before each Component is built
17288 * can be used to apply permissions.
17289 * @param {Roo.XComponent} c the component being registerd.
17292 'beforebuild' : true,
17294 * @event buildcomplete
17295 * Fires on the top level element when all elements have been built
17296 * @param {Roo.XComponent} the top level component.
17298 'buildcomplete' : true
17303 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17306 * marked - a markdown parser
17307 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17308 * https://github.com/chjj/marked
17314 * Roo.Markdown - is a very crude wrapper around marked..
17318 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17320 * Note: move the sample code to the bottom of this
17321 * file before uncommenting it.
17326 Roo.Markdown.toHtml = function(text) {
17328 var c = new Roo.Markdown.marked.setOptions({
17329 renderer: new Roo.Markdown.marked.Renderer(),
17340 text = text.replace(/\\\n/g,' ');
17341 return Roo.Markdown.marked(text);
17346 // Wraps all "globals" so that the only thing
17347 // exposed is makeHtml().
17353 * eval:var:unescape
17361 var escape = function (html, encode) {
17363 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17364 .replace(/</g, '<')
17365 .replace(/>/g, '>')
17366 .replace(/"/g, '"')
17367 .replace(/'/g, ''');
17370 var unescape = function (html) {
17371 // explicitly match decimal, hex, and named HTML entities
17372 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17373 n = n.toLowerCase();
17374 if (n === 'colon') { return ':'; }
17375 if (n.charAt(0) === '#') {
17376 return n.charAt(1) === 'x'
17377 ? String.fromCharCode(parseInt(n.substring(2), 16))
17378 : String.fromCharCode(+n.substring(1));
17384 var replace = function (regex, opt) {
17385 regex = regex.source;
17387 return function self(name, val) {
17388 if (!name) { return new RegExp(regex, opt); }
17389 val = val.source || val;
17390 val = val.replace(/(^|[^\[])\^/g, '$1');
17391 regex = regex.replace(name, val);
17400 var noop = function () {}
17406 var merge = function (obj) {
17411 for (; i < arguments.length; i++) {
17412 target = arguments[i];
17413 for (key in target) {
17414 if (Object.prototype.hasOwnProperty.call(target, key)) {
17415 obj[key] = target[key];
17425 * Block-Level Grammar
17433 code: /^( {4}[^\n]+\n*)+/,
17435 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17436 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17438 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17439 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17440 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17441 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17442 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17444 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17448 block.bullet = /(?:[*+-]|\d+\.)/;
17449 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17450 block.item = replace(block.item, 'gm')
17451 (/bull/g, block.bullet)
17454 block.list = replace(block.list)
17455 (/bull/g, block.bullet)
17456 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17457 ('def', '\\n+(?=' + block.def.source + ')')
17460 block.blockquote = replace(block.blockquote)
17464 block._tag = '(?!(?:'
17465 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17466 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17467 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17469 block.html = replace(block.html)
17470 ('comment', /<!--[\s\S]*?-->/)
17471 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17472 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17473 (/tag/g, block._tag)
17476 block.paragraph = replace(block.paragraph)
17478 ('heading', block.heading)
17479 ('lheading', block.lheading)
17480 ('blockquote', block.blockquote)
17481 ('tag', '<' + block._tag)
17486 * Normal Block Grammar
17489 block.normal = merge({}, block);
17492 * GFM Block Grammar
17495 block.gfm = merge({}, block.normal, {
17496 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17498 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17501 block.gfm.paragraph = replace(block.paragraph)
17503 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17504 + block.list.source.replace('\\1', '\\3') + '|')
17508 * GFM + Tables Block Grammar
17511 block.tables = merge({}, block.gfm, {
17512 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17513 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17520 var Lexer = function (options) {
17522 this.tokens.links = {};
17523 this.options = options || marked.defaults;
17524 this.rules = block.normal;
17526 if (this.options.gfm) {
17527 if (this.options.tables) {
17528 this.rules = block.tables;
17530 this.rules = block.gfm;
17536 * Expose Block Rules
17539 Lexer.rules = block;
17542 * Static Lex Method
17545 Lexer.lex = function(src, options) {
17546 var lexer = new Lexer(options);
17547 return lexer.lex(src);
17554 Lexer.prototype.lex = function(src) {
17556 .replace(/\r\n|\r/g, '\n')
17557 .replace(/\t/g, ' ')
17558 .replace(/\u00a0/g, ' ')
17559 .replace(/\u2424/g, '\n');
17561 return this.token(src, true);
17568 Lexer.prototype.token = function(src, top, bq) {
17569 var src = src.replace(/^ +$/gm, '')
17582 if (cap = this.rules.newline.exec(src)) {
17583 src = src.substring(cap[0].length);
17584 if (cap[0].length > 1) {
17592 if (cap = this.rules.code.exec(src)) {
17593 src = src.substring(cap[0].length);
17594 cap = cap[0].replace(/^ {4}/gm, '');
17597 text: !this.options.pedantic
17598 ? cap.replace(/\n+$/, '')
17605 if (cap = this.rules.fences.exec(src)) {
17606 src = src.substring(cap[0].length);
17616 if (cap = this.rules.heading.exec(src)) {
17617 src = src.substring(cap[0].length);
17620 depth: cap[1].length,
17626 // table no leading pipe (gfm)
17627 if (top && (cap = this.rules.nptable.exec(src))) {
17628 src = src.substring(cap[0].length);
17632 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17633 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17634 cells: cap[3].replace(/\n$/, '').split('\n')
17637 for (i = 0; i < item.align.length; i++) {
17638 if (/^ *-+: *$/.test(item.align[i])) {
17639 item.align[i] = 'right';
17640 } else if (/^ *:-+: *$/.test(item.align[i])) {
17641 item.align[i] = 'center';
17642 } else if (/^ *:-+ *$/.test(item.align[i])) {
17643 item.align[i] = 'left';
17645 item.align[i] = null;
17649 for (i = 0; i < item.cells.length; i++) {
17650 item.cells[i] = item.cells[i].split(/ *\| */);
17653 this.tokens.push(item);
17659 if (cap = this.rules.lheading.exec(src)) {
17660 src = src.substring(cap[0].length);
17663 depth: cap[2] === '=' ? 1 : 2,
17670 if (cap = this.rules.hr.exec(src)) {
17671 src = src.substring(cap[0].length);
17679 if (cap = this.rules.blockquote.exec(src)) {
17680 src = src.substring(cap[0].length);
17683 type: 'blockquote_start'
17686 cap = cap[0].replace(/^ *> ?/gm, '');
17688 // Pass `top` to keep the current
17689 // "toplevel" state. This is exactly
17690 // how markdown.pl works.
17691 this.token(cap, top, true);
17694 type: 'blockquote_end'
17701 if (cap = this.rules.list.exec(src)) {
17702 src = src.substring(cap[0].length);
17706 type: 'list_start',
17707 ordered: bull.length > 1
17710 // Get each top-level item.
17711 cap = cap[0].match(this.rules.item);
17717 for (; i < l; i++) {
17720 // Remove the list item's bullet
17721 // so it is seen as the next token.
17722 space = item.length;
17723 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17725 // Outdent whatever the
17726 // list item contains. Hacky.
17727 if (~item.indexOf('\n ')) {
17728 space -= item.length;
17729 item = !this.options.pedantic
17730 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17731 : item.replace(/^ {1,4}/gm, '');
17734 // Determine whether the next list item belongs here.
17735 // Backpedal if it does not belong in this list.
17736 if (this.options.smartLists && i !== l - 1) {
17737 b = block.bullet.exec(cap[i + 1])[0];
17738 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17739 src = cap.slice(i + 1).join('\n') + src;
17744 // Determine whether item is loose or not.
17745 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17746 // for discount behavior.
17747 loose = next || /\n\n(?!\s*$)/.test(item);
17749 next = item.charAt(item.length - 1) === '\n';
17750 if (!loose) { loose = next; }
17755 ? 'loose_item_start'
17756 : 'list_item_start'
17760 this.token(item, false, bq);
17763 type: 'list_item_end'
17775 if (cap = this.rules.html.exec(src)) {
17776 src = src.substring(cap[0].length);
17778 type: this.options.sanitize
17781 pre: !this.options.sanitizer
17782 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17789 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17790 src = src.substring(cap[0].length);
17791 this.tokens.links[cap[1].toLowerCase()] = {
17799 if (top && (cap = this.rules.table.exec(src))) {
17800 src = src.substring(cap[0].length);
17804 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17805 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17806 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17809 for (i = 0; i < item.align.length; i++) {
17810 if (/^ *-+: *$/.test(item.align[i])) {
17811 item.align[i] = 'right';
17812 } else if (/^ *:-+: *$/.test(item.align[i])) {
17813 item.align[i] = 'center';
17814 } else if (/^ *:-+ *$/.test(item.align[i])) {
17815 item.align[i] = 'left';
17817 item.align[i] = null;
17821 for (i = 0; i < item.cells.length; i++) {
17822 item.cells[i] = item.cells[i]
17823 .replace(/^ *\| *| *\| *$/g, '')
17827 this.tokens.push(item);
17832 // top-level paragraph
17833 if (top && (cap = this.rules.paragraph.exec(src))) {
17834 src = src.substring(cap[0].length);
17837 text: cap[1].charAt(cap[1].length - 1) === '\n'
17838 ? cap[1].slice(0, -1)
17845 if (cap = this.rules.text.exec(src)) {
17846 // Top-level should never reach here.
17847 src = src.substring(cap[0].length);
17857 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17861 return this.tokens;
17865 * Inline-Level Grammar
17869 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17870 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17872 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17873 link: /^!?\[(inside)\]\(href\)/,
17874 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17875 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17876 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17877 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17878 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17879 br: /^ {2,}\n(?!\s*$)/,
17881 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17884 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17885 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17887 inline.link = replace(inline.link)
17888 ('inside', inline._inside)
17889 ('href', inline._href)
17892 inline.reflink = replace(inline.reflink)
17893 ('inside', inline._inside)
17897 * Normal Inline Grammar
17900 inline.normal = merge({}, inline);
17903 * Pedantic Inline Grammar
17906 inline.pedantic = merge({}, inline.normal, {
17907 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17908 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17912 * GFM Inline Grammar
17915 inline.gfm = merge({}, inline.normal, {
17916 escape: replace(inline.escape)('])', '~|])')(),
17917 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17918 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17919 text: replace(inline.text)
17921 ('|', '|https?://|')
17926 * GFM + Line Breaks Inline Grammar
17929 inline.breaks = merge({}, inline.gfm, {
17930 br: replace(inline.br)('{2,}', '*')(),
17931 text: replace(inline.gfm.text)('{2,}', '*')()
17935 * Inline Lexer & Compiler
17938 var InlineLexer = function (links, options) {
17939 this.options = options || marked.defaults;
17940 this.links = links;
17941 this.rules = inline.normal;
17942 this.renderer = this.options.renderer || new Renderer;
17943 this.renderer.options = this.options;
17947 Error('Tokens array requires a `links` property.');
17950 if (this.options.gfm) {
17951 if (this.options.breaks) {
17952 this.rules = inline.breaks;
17954 this.rules = inline.gfm;
17956 } else if (this.options.pedantic) {
17957 this.rules = inline.pedantic;
17962 * Expose Inline Rules
17965 InlineLexer.rules = inline;
17968 * Static Lexing/Compiling Method
17971 InlineLexer.output = function(src, links, options) {
17972 var inline = new InlineLexer(links, options);
17973 return inline.output(src);
17980 InlineLexer.prototype.output = function(src) {
17989 if (cap = this.rules.escape.exec(src)) {
17990 src = src.substring(cap[0].length);
17996 if (cap = this.rules.autolink.exec(src)) {
17997 src = src.substring(cap[0].length);
17998 if (cap[2] === '@') {
17999 text = cap[1].charAt(6) === ':'
18000 ? this.mangle(cap[1].substring(7))
18001 : this.mangle(cap[1]);
18002 href = this.mangle('mailto:') + text;
18004 text = escape(cap[1]);
18007 out += this.renderer.link(href, null, text);
18012 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18013 src = src.substring(cap[0].length);
18014 text = escape(cap[1]);
18016 out += this.renderer.link(href, null, text);
18021 if (cap = this.rules.tag.exec(src)) {
18022 if (!this.inLink && /^<a /i.test(cap[0])) {
18023 this.inLink = true;
18024 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18025 this.inLink = false;
18027 src = src.substring(cap[0].length);
18028 out += this.options.sanitize
18029 ? this.options.sanitizer
18030 ? this.options.sanitizer(cap[0])
18037 if (cap = this.rules.link.exec(src)) {
18038 src = src.substring(cap[0].length);
18039 this.inLink = true;
18040 out += this.outputLink(cap, {
18044 this.inLink = false;
18049 if ((cap = this.rules.reflink.exec(src))
18050 || (cap = this.rules.nolink.exec(src))) {
18051 src = src.substring(cap[0].length);
18052 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18053 link = this.links[link.toLowerCase()];
18054 if (!link || !link.href) {
18055 out += cap[0].charAt(0);
18056 src = cap[0].substring(1) + src;
18059 this.inLink = true;
18060 out += this.outputLink(cap, link);
18061 this.inLink = false;
18066 if (cap = this.rules.strong.exec(src)) {
18067 src = src.substring(cap[0].length);
18068 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18073 if (cap = this.rules.em.exec(src)) {
18074 src = src.substring(cap[0].length);
18075 out += this.renderer.em(this.output(cap[2] || cap[1]));
18080 if (cap = this.rules.code.exec(src)) {
18081 src = src.substring(cap[0].length);
18082 out += this.renderer.codespan(escape(cap[2], true));
18087 if (cap = this.rules.br.exec(src)) {
18088 src = src.substring(cap[0].length);
18089 out += this.renderer.br();
18094 if (cap = this.rules.del.exec(src)) {
18095 src = src.substring(cap[0].length);
18096 out += this.renderer.del(this.output(cap[1]));
18101 if (cap = this.rules.text.exec(src)) {
18102 src = src.substring(cap[0].length);
18103 out += this.renderer.text(escape(this.smartypants(cap[0])));
18109 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18120 InlineLexer.prototype.outputLink = function(cap, link) {
18121 var href = escape(link.href)
18122 , title = link.title ? escape(link.title) : null;
18124 return cap[0].charAt(0) !== '!'
18125 ? this.renderer.link(href, title, this.output(cap[1]))
18126 : this.renderer.image(href, title, escape(cap[1]));
18130 * Smartypants Transformations
18133 InlineLexer.prototype.smartypants = function(text) {
18134 if (!this.options.smartypants) { return text; }
18137 .replace(/---/g, '\u2014')
18139 .replace(/--/g, '\u2013')
18141 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18142 // closing singles & apostrophes
18143 .replace(/'/g, '\u2019')
18145 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18147 .replace(/"/g, '\u201d')
18149 .replace(/\.{3}/g, '\u2026');
18156 InlineLexer.prototype.mangle = function(text) {
18157 if (!this.options.mangle) { return text; }
18163 for (; i < l; i++) {
18164 ch = text.charCodeAt(i);
18165 if (Math.random() > 0.5) {
18166 ch = 'x' + ch.toString(16);
18168 out += '&#' + ch + ';';
18179 * eval:var:Renderer
18182 var Renderer = function (options) {
18183 this.options = options || {};
18186 Renderer.prototype.code = function(code, lang, escaped) {
18187 if (this.options.highlight) {
18188 var out = this.options.highlight(code, lang);
18189 if (out != null && out !== code) {
18194 // hack!!! - it's already escapeD?
18199 return '<pre><code>'
18200 + (escaped ? code : escape(code, true))
18201 + '\n</code></pre>';
18204 return '<pre><code class="'
18205 + this.options.langPrefix
18206 + escape(lang, true)
18208 + (escaped ? code : escape(code, true))
18209 + '\n</code></pre>\n';
18212 Renderer.prototype.blockquote = function(quote) {
18213 return '<blockquote>\n' + quote + '</blockquote>\n';
18216 Renderer.prototype.html = function(html) {
18220 Renderer.prototype.heading = function(text, level, raw) {
18224 + this.options.headerPrefix
18225 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18233 Renderer.prototype.hr = function() {
18234 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18237 Renderer.prototype.list = function(body, ordered) {
18238 var type = ordered ? 'ol' : 'ul';
18239 return '<' + type + '>\n' + body + '</' + type + '>\n';
18242 Renderer.prototype.listitem = function(text) {
18243 return '<li>' + text + '</li>\n';
18246 Renderer.prototype.paragraph = function(text) {
18247 return '<p>' + text + '</p>\n';
18250 Renderer.prototype.table = function(header, body) {
18251 return '<table class="table table-striped">\n'
18261 Renderer.prototype.tablerow = function(content) {
18262 return '<tr>\n' + content + '</tr>\n';
18265 Renderer.prototype.tablecell = function(content, flags) {
18266 var type = flags.header ? 'th' : 'td';
18267 var tag = flags.align
18268 ? '<' + type + ' style="text-align:' + flags.align + '">'
18269 : '<' + type + '>';
18270 return tag + content + '</' + type + '>\n';
18273 // span level renderer
18274 Renderer.prototype.strong = function(text) {
18275 return '<strong>' + text + '</strong>';
18278 Renderer.prototype.em = function(text) {
18279 return '<em>' + text + '</em>';
18282 Renderer.prototype.codespan = function(text) {
18283 return '<code>' + text + '</code>';
18286 Renderer.prototype.br = function() {
18287 return this.options.xhtml ? '<br/>' : '<br>';
18290 Renderer.prototype.del = function(text) {
18291 return '<del>' + text + '</del>';
18294 Renderer.prototype.link = function(href, title, text) {
18295 if (this.options.sanitize) {
18297 var prot = decodeURIComponent(unescape(href))
18298 .replace(/[^\w:]/g, '')
18303 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18307 var out = '<a href="' + href + '"';
18309 out += ' title="' + title + '"';
18311 out += '>' + text + '</a>';
18315 Renderer.prototype.image = function(href, title, text) {
18316 var out = '<img src="' + href + '" alt="' + text + '"';
18318 out += ' title="' + title + '"';
18320 out += this.options.xhtml ? '/>' : '>';
18324 Renderer.prototype.text = function(text) {
18329 * Parsing & Compiling
18335 var Parser= function (options) {
18338 this.options = options || marked.defaults;
18339 this.options.renderer = this.options.renderer || new Renderer;
18340 this.renderer = this.options.renderer;
18341 this.renderer.options = this.options;
18345 * Static Parse Method
18348 Parser.parse = function(src, options, renderer) {
18349 var parser = new Parser(options, renderer);
18350 return parser.parse(src);
18357 Parser.prototype.parse = function(src) {
18358 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18359 this.tokens = src.reverse();
18362 while (this.next()) {
18373 Parser.prototype.next = function() {
18374 return this.token = this.tokens.pop();
18378 * Preview Next Token
18381 Parser.prototype.peek = function() {
18382 return this.tokens[this.tokens.length - 1] || 0;
18386 * Parse Text Tokens
18389 Parser.prototype.parseText = function() {
18390 var body = this.token.text;
18392 while (this.peek().type === 'text') {
18393 body += '\n' + this.next().text;
18396 return this.inline.output(body);
18400 * Parse Current Token
18403 Parser.prototype.tok = function() {
18404 switch (this.token.type) {
18409 return this.renderer.hr();
18412 return this.renderer.heading(
18413 this.inline.output(this.token.text),
18418 return this.renderer.code(this.token.text,
18420 this.token.escaped);
18433 for (i = 0; i < this.token.header.length; i++) {
18434 flags = { header: true, align: this.token.align[i] };
18435 cell += this.renderer.tablecell(
18436 this.inline.output(this.token.header[i]),
18437 { header: true, align: this.token.align[i] }
18440 header += this.renderer.tablerow(cell);
18442 for (i = 0; i < this.token.cells.length; i++) {
18443 row = this.token.cells[i];
18446 for (j = 0; j < row.length; j++) {
18447 cell += this.renderer.tablecell(
18448 this.inline.output(row[j]),
18449 { header: false, align: this.token.align[j] }
18453 body += this.renderer.tablerow(cell);
18455 return this.renderer.table(header, body);
18457 case 'blockquote_start': {
18460 while (this.next().type !== 'blockquote_end') {
18461 body += this.tok();
18464 return this.renderer.blockquote(body);
18466 case 'list_start': {
18468 , ordered = this.token.ordered;
18470 while (this.next().type !== 'list_end') {
18471 body += this.tok();
18474 return this.renderer.list(body, ordered);
18476 case 'list_item_start': {
18479 while (this.next().type !== 'list_item_end') {
18480 body += this.token.type === 'text'
18485 return this.renderer.listitem(body);
18487 case 'loose_item_start': {
18490 while (this.next().type !== 'list_item_end') {
18491 body += this.tok();
18494 return this.renderer.listitem(body);
18497 var html = !this.token.pre && !this.options.pedantic
18498 ? this.inline.output(this.token.text)
18500 return this.renderer.html(html);
18502 case 'paragraph': {
18503 return this.renderer.paragraph(this.inline.output(this.token.text));
18506 return this.renderer.paragraph(this.parseText());
18518 var marked = function (src, opt, callback) {
18519 if (callback || typeof opt === 'function') {
18525 opt = merge({}, marked.defaults, opt || {});
18527 var highlight = opt.highlight
18533 tokens = Lexer.lex(src, opt)
18535 return callback(e);
18538 pending = tokens.length;
18542 var done = function(err) {
18544 opt.highlight = highlight;
18545 return callback(err);
18551 out = Parser.parse(tokens, opt);
18556 opt.highlight = highlight;
18560 : callback(null, out);
18563 if (!highlight || highlight.length < 3) {
18567 delete opt.highlight;
18569 if (!pending) { return done(); }
18571 for (; i < tokens.length; i++) {
18573 if (token.type !== 'code') {
18574 return --pending || done();
18576 return highlight(token.text, token.lang, function(err, code) {
18577 if (err) { return done(err); }
18578 if (code == null || code === token.text) {
18579 return --pending || done();
18582 token.escaped = true;
18583 --pending || done();
18591 if (opt) { opt = merge({}, marked.defaults, opt); }
18592 return Parser.parse(Lexer.lex(src, opt), opt);
18594 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18595 if ((opt || marked.defaults).silent) {
18596 return '<p>An error occured:</p><pre>'
18597 + escape(e.message + '', true)
18609 marked.setOptions = function(opt) {
18610 merge(marked.defaults, opt);
18614 marked.defaults = {
18625 langPrefix: 'lang-',
18626 smartypants: false,
18628 renderer: new Renderer,
18636 marked.Parser = Parser;
18637 marked.parser = Parser.parse;
18639 marked.Renderer = Renderer;
18641 marked.Lexer = Lexer;
18642 marked.lexer = Lexer.lex;
18644 marked.InlineLexer = InlineLexer;
18645 marked.inlineLexer = InlineLexer.output;
18647 marked.parse = marked;
18649 Roo.Markdown.marked = marked;
18653 * Ext JS Library 1.1.1
18654 * Copyright(c) 2006-2007, Ext JS, LLC.
18656 * Originally Released Under LGPL - original licence link has changed is not relivant.
18659 * <script type="text/javascript">
18665 * These classes are derivatives of the similarly named classes in the YUI Library.
18666 * The original license:
18667 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18668 * Code licensed under the BSD License:
18669 * http://developer.yahoo.net/yui/license.txt
18674 var Event=Roo.EventManager;
18675 var Dom=Roo.lib.Dom;
18678 * @class Roo.dd.DragDrop
18679 * @extends Roo.util.Observable
18680 * Defines the interface and base operation of items that that can be
18681 * dragged or can be drop targets. It was designed to be extended, overriding
18682 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18683 * Up to three html elements can be associated with a DragDrop instance:
18685 * <li>linked element: the element that is passed into the constructor.
18686 * This is the element which defines the boundaries for interaction with
18687 * other DragDrop objects.</li>
18688 * <li>handle element(s): The drag operation only occurs if the element that
18689 * was clicked matches a handle element. By default this is the linked
18690 * element, but there are times that you will want only a portion of the
18691 * linked element to initiate the drag operation, and the setHandleElId()
18692 * method provides a way to define this.</li>
18693 * <li>drag element: this represents the element that would be moved along
18694 * with the cursor during a drag operation. By default, this is the linked
18695 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18696 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18699 * This class should not be instantiated until the onload event to ensure that
18700 * the associated elements are available.
18701 * The following would define a DragDrop obj that would interact with any
18702 * other DragDrop obj in the "group1" group:
18704 * dd = new Roo.dd.DragDrop("div1", "group1");
18706 * Since none of the event handlers have been implemented, nothing would
18707 * actually happen if you were to run the code above. Normally you would
18708 * override this class or one of the default implementations, but you can
18709 * also override the methods you want on an instance of the class...
18711 * dd.onDragDrop = function(e, id) {
18712 * alert("dd was dropped on " + id);
18716 * @param {String} id of the element that is linked to this instance
18717 * @param {String} sGroup the group of related DragDrop objects
18718 * @param {object} config an object containing configurable attributes
18719 * Valid properties for DragDrop:
18720 * padding, isTarget, maintainOffset, primaryButtonOnly
18722 Roo.dd.DragDrop = function(id, sGroup, config) {
18724 this.init(id, sGroup, config);
18729 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18732 * The id of the element associated with this object. This is what we
18733 * refer to as the "linked element" because the size and position of
18734 * this element is used to determine when the drag and drop objects have
18742 * Configuration attributes passed into the constructor
18749 * The id of the element that will be dragged. By default this is same
18750 * as the linked element , but could be changed to another element. Ex:
18752 * @property dragElId
18759 * the id of the element that initiates the drag operation. By default
18760 * this is the linked element, but could be changed to be a child of this
18761 * element. This lets us do things like only starting the drag when the
18762 * header element within the linked html element is clicked.
18763 * @property handleElId
18770 * An associative array of HTML tags that will be ignored if clicked.
18771 * @property invalidHandleTypes
18772 * @type {string: string}
18774 invalidHandleTypes: null,
18777 * An associative array of ids for elements that will be ignored if clicked
18778 * @property invalidHandleIds
18779 * @type {string: string}
18781 invalidHandleIds: null,
18784 * An indexted array of css class names for elements that will be ignored
18786 * @property invalidHandleClasses
18789 invalidHandleClasses: null,
18792 * The linked element's absolute X position at the time the drag was
18794 * @property startPageX
18801 * The linked element's absolute X position at the time the drag was
18803 * @property startPageY
18810 * The group defines a logical collection of DragDrop objects that are
18811 * related. Instances only get events when interacting with other
18812 * DragDrop object in the same group. This lets us define multiple
18813 * groups using a single DragDrop subclass if we want.
18815 * @type {string: string}
18820 * Individual drag/drop instances can be locked. This will prevent
18821 * onmousedown start drag.
18829 * Lock this instance
18832 lock: function() { this.locked = true; },
18835 * Unlock this instace
18838 unlock: function() { this.locked = false; },
18841 * By default, all insances can be a drop target. This can be disabled by
18842 * setting isTarget to false.
18849 * The padding configured for this drag and drop object for calculating
18850 * the drop zone intersection with this object.
18857 * Cached reference to the linked element
18858 * @property _domRef
18864 * Internal typeof flag
18865 * @property __ygDragDrop
18868 __ygDragDrop: true,
18871 * Set to true when horizontal contraints are applied
18872 * @property constrainX
18879 * Set to true when vertical contraints are applied
18880 * @property constrainY
18887 * The left constraint
18895 * The right constraint
18903 * The up constraint
18912 * The down constraint
18920 * Maintain offsets when we resetconstraints. Set to true when you want
18921 * the position of the element relative to its parent to stay the same
18922 * when the page changes
18924 * @property maintainOffset
18927 maintainOffset: false,
18930 * Array of pixel locations the element will snap to if we specified a
18931 * horizontal graduation/interval. This array is generated automatically
18932 * when you define a tick interval.
18939 * Array of pixel locations the element will snap to if we specified a
18940 * vertical graduation/interval. This array is generated automatically
18941 * when you define a tick interval.
18948 * By default the drag and drop instance will only respond to the primary
18949 * button click (left button for a right-handed mouse). Set to true to
18950 * allow drag and drop to start with any mouse click that is propogated
18952 * @property primaryButtonOnly
18955 primaryButtonOnly: true,
18958 * The availabe property is false until the linked dom element is accessible.
18959 * @property available
18965 * By default, drags can only be initiated if the mousedown occurs in the
18966 * region the linked element is. This is done in part to work around a
18967 * bug in some browsers that mis-report the mousedown if the previous
18968 * mouseup happened outside of the window. This property is set to true
18969 * if outer handles are defined.
18971 * @property hasOuterHandles
18975 hasOuterHandles: false,
18978 * Code that executes immediately before the startDrag event
18979 * @method b4StartDrag
18982 b4StartDrag: function(x, y) { },
18985 * Abstract method called after a drag/drop object is clicked
18986 * and the drag or mousedown time thresholds have beeen met.
18987 * @method startDrag
18988 * @param {int} X click location
18989 * @param {int} Y click location
18991 startDrag: function(x, y) { /* override this */ },
18994 * Code that executes immediately before the onDrag event
18998 b4Drag: function(e) { },
19001 * Abstract method called during the onMouseMove event while dragging an
19004 * @param {Event} e the mousemove event
19006 onDrag: function(e) { /* override this */ },
19009 * Abstract method called when this element fist begins hovering over
19010 * another DragDrop obj
19011 * @method onDragEnter
19012 * @param {Event} e the mousemove event
19013 * @param {String|DragDrop[]} id In POINT mode, the element
19014 * id this is hovering over. In INTERSECT mode, an array of one or more
19015 * dragdrop items being hovered over.
19017 onDragEnter: function(e, id) { /* override this */ },
19020 * Code that executes immediately before the onDragOver event
19021 * @method b4DragOver
19024 b4DragOver: function(e) { },
19027 * Abstract method called when this element is hovering over another
19029 * @method onDragOver
19030 * @param {Event} e the mousemove event
19031 * @param {String|DragDrop[]} id In POINT mode, the element
19032 * id this is hovering over. In INTERSECT mode, an array of dd items
19033 * being hovered over.
19035 onDragOver: function(e, id) { /* override this */ },
19038 * Code that executes immediately before the onDragOut event
19039 * @method b4DragOut
19042 b4DragOut: function(e) { },
19045 * Abstract method called when we are no longer hovering over an element
19046 * @method onDragOut
19047 * @param {Event} e the mousemove event
19048 * @param {String|DragDrop[]} id In POINT mode, the element
19049 * id this was hovering over. In INTERSECT mode, an array of dd items
19050 * that the mouse is no longer over.
19052 onDragOut: function(e, id) { /* override this */ },
19055 * Code that executes immediately before the onDragDrop event
19056 * @method b4DragDrop
19059 b4DragDrop: function(e) { },
19062 * Abstract method called when this item is dropped on another DragDrop
19064 * @method onDragDrop
19065 * @param {Event} e the mouseup event
19066 * @param {String|DragDrop[]} id In POINT mode, the element
19067 * id this was dropped on. In INTERSECT mode, an array of dd items this
19070 onDragDrop: function(e, id) { /* override this */ },
19073 * Abstract method called when this item is dropped on an area with no
19075 * @method onInvalidDrop
19076 * @param {Event} e the mouseup event
19078 onInvalidDrop: function(e) { /* override this */ },
19081 * Code that executes immediately before the endDrag event
19082 * @method b4EndDrag
19085 b4EndDrag: function(e) { },
19088 * Fired when we are done dragging the object
19090 * @param {Event} e the mouseup event
19092 endDrag: function(e) { /* override this */ },
19095 * Code executed immediately before the onMouseDown event
19096 * @method b4MouseDown
19097 * @param {Event} e the mousedown event
19100 b4MouseDown: function(e) { },
19103 * Event handler that fires when a drag/drop obj gets a mousedown
19104 * @method onMouseDown
19105 * @param {Event} e the mousedown event
19107 onMouseDown: function(e) { /* override this */ },
19110 * Event handler that fires when a drag/drop obj gets a mouseup
19111 * @method onMouseUp
19112 * @param {Event} e the mouseup event
19114 onMouseUp: function(e) { /* override this */ },
19117 * Override the onAvailable method to do what is needed after the initial
19118 * position was determined.
19119 * @method onAvailable
19121 onAvailable: function () {
19125 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19128 defaultPadding : {left:0, right:0, top:0, bottom:0},
19131 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19135 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19136 { dragElId: "existingProxyDiv" });
19137 dd.startDrag = function(){
19138 this.constrainTo("parent-id");
19141 * Or you can initalize it using the {@link Roo.Element} object:
19143 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19144 startDrag : function(){
19145 this.constrainTo("parent-id");
19149 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19150 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19151 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19152 * an object containing the sides to pad. For example: {right:10, bottom:10}
19153 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19155 constrainTo : function(constrainTo, pad, inContent){
19156 if(typeof pad == "number"){
19157 pad = {left: pad, right:pad, top:pad, bottom:pad};
19159 pad = pad || this.defaultPadding;
19160 var b = Roo.get(this.getEl()).getBox();
19161 var ce = Roo.get(constrainTo);
19162 var s = ce.getScroll();
19163 var c, cd = ce.dom;
19164 if(cd == document.body){
19165 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19168 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19172 var topSpace = b.y - c.y;
19173 var leftSpace = b.x - c.x;
19175 this.resetConstraints();
19176 this.setXConstraint(leftSpace - (pad.left||0), // left
19177 c.width - leftSpace - b.width - (pad.right||0) //right
19179 this.setYConstraint(topSpace - (pad.top||0), //top
19180 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19185 * Returns a reference to the linked element
19187 * @return {HTMLElement} the html element
19189 getEl: function() {
19190 if (!this._domRef) {
19191 this._domRef = Roo.getDom(this.id);
19194 return this._domRef;
19198 * Returns a reference to the actual element to drag. By default this is
19199 * the same as the html element, but it can be assigned to another
19200 * element. An example of this can be found in Roo.dd.DDProxy
19201 * @method getDragEl
19202 * @return {HTMLElement} the html element
19204 getDragEl: function() {
19205 return Roo.getDom(this.dragElId);
19209 * Sets up the DragDrop object. Must be called in the constructor of any
19210 * Roo.dd.DragDrop subclass
19212 * @param id the id of the linked element
19213 * @param {String} sGroup the group of related items
19214 * @param {object} config configuration attributes
19216 init: function(id, sGroup, config) {
19217 this.initTarget(id, sGroup, config);
19218 if (!Roo.isTouch) {
19219 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19221 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19222 // Event.on(this.id, "selectstart", Event.preventDefault);
19226 * Initializes Targeting functionality only... the object does not
19227 * get a mousedown handler.
19228 * @method initTarget
19229 * @param id the id of the linked element
19230 * @param {String} sGroup the group of related items
19231 * @param {object} config configuration attributes
19233 initTarget: function(id, sGroup, config) {
19235 // configuration attributes
19236 this.config = config || {};
19238 // create a local reference to the drag and drop manager
19239 this.DDM = Roo.dd.DDM;
19240 // initialize the groups array
19243 // assume that we have an element reference instead of an id if the
19244 // parameter is not a string
19245 if (typeof id !== "string") {
19252 // add to an interaction group
19253 this.addToGroup((sGroup) ? sGroup : "default");
19255 // We don't want to register this as the handle with the manager
19256 // so we just set the id rather than calling the setter.
19257 this.handleElId = id;
19259 // the linked element is the element that gets dragged by default
19260 this.setDragElId(id);
19262 // by default, clicked anchors will not start drag operations.
19263 this.invalidHandleTypes = { A: "A" };
19264 this.invalidHandleIds = {};
19265 this.invalidHandleClasses = [];
19267 this.applyConfig();
19269 this.handleOnAvailable();
19273 * Applies the configuration parameters that were passed into the constructor.
19274 * This is supposed to happen at each level through the inheritance chain. So
19275 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19276 * DragDrop in order to get all of the parameters that are available in
19278 * @method applyConfig
19280 applyConfig: function() {
19282 // configurable properties:
19283 // padding, isTarget, maintainOffset, primaryButtonOnly
19284 this.padding = this.config.padding || [0, 0, 0, 0];
19285 this.isTarget = (this.config.isTarget !== false);
19286 this.maintainOffset = (this.config.maintainOffset);
19287 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19292 * Executed when the linked element is available
19293 * @method handleOnAvailable
19296 handleOnAvailable: function() {
19297 this.available = true;
19298 this.resetConstraints();
19299 this.onAvailable();
19303 * Configures the padding for the target zone in px. Effectively expands
19304 * (or reduces) the virtual object size for targeting calculations.
19305 * Supports css-style shorthand; if only one parameter is passed, all sides
19306 * will have that padding, and if only two are passed, the top and bottom
19307 * will have the first param, the left and right the second.
19308 * @method setPadding
19309 * @param {int} iTop Top pad
19310 * @param {int} iRight Right pad
19311 * @param {int} iBot Bot pad
19312 * @param {int} iLeft Left pad
19314 setPadding: function(iTop, iRight, iBot, iLeft) {
19315 // this.padding = [iLeft, iRight, iTop, iBot];
19316 if (!iRight && 0 !== iRight) {
19317 this.padding = [iTop, iTop, iTop, iTop];
19318 } else if (!iBot && 0 !== iBot) {
19319 this.padding = [iTop, iRight, iTop, iRight];
19321 this.padding = [iTop, iRight, iBot, iLeft];
19326 * Stores the initial placement of the linked element.
19327 * @method setInitialPosition
19328 * @param {int} diffX the X offset, default 0
19329 * @param {int} diffY the Y offset, default 0
19331 setInitPosition: function(diffX, diffY) {
19332 var el = this.getEl();
19334 if (!this.DDM.verifyEl(el)) {
19338 var dx = diffX || 0;
19339 var dy = diffY || 0;
19341 var p = Dom.getXY( el );
19343 this.initPageX = p[0] - dx;
19344 this.initPageY = p[1] - dy;
19346 this.lastPageX = p[0];
19347 this.lastPageY = p[1];
19350 this.setStartPosition(p);
19354 * Sets the start position of the element. This is set when the obj
19355 * is initialized, the reset when a drag is started.
19356 * @method setStartPosition
19357 * @param pos current position (from previous lookup)
19360 setStartPosition: function(pos) {
19361 var p = pos || Dom.getXY( this.getEl() );
19362 this.deltaSetXY = null;
19364 this.startPageX = p[0];
19365 this.startPageY = p[1];
19369 * Add this instance to a group of related drag/drop objects. All
19370 * instances belong to at least one group, and can belong to as many
19371 * groups as needed.
19372 * @method addToGroup
19373 * @param sGroup {string} the name of the group
19375 addToGroup: function(sGroup) {
19376 this.groups[sGroup] = true;
19377 this.DDM.regDragDrop(this, sGroup);
19381 * Remove's this instance from the supplied interaction group
19382 * @method removeFromGroup
19383 * @param {string} sGroup The group to drop
19385 removeFromGroup: function(sGroup) {
19386 if (this.groups[sGroup]) {
19387 delete this.groups[sGroup];
19390 this.DDM.removeDDFromGroup(this, sGroup);
19394 * Allows you to specify that an element other than the linked element
19395 * will be moved with the cursor during a drag
19396 * @method setDragElId
19397 * @param id {string} the id of the element that will be used to initiate the drag
19399 setDragElId: function(id) {
19400 this.dragElId = id;
19404 * Allows you to specify a child of the linked element that should be
19405 * used to initiate the drag operation. An example of this would be if
19406 * you have a content div with text and links. Clicking anywhere in the
19407 * content area would normally start the drag operation. Use this method
19408 * to specify that an element inside of the content div is the element
19409 * that starts the drag operation.
19410 * @method setHandleElId
19411 * @param id {string} the id of the element that will be used to
19412 * initiate the drag.
19414 setHandleElId: function(id) {
19415 if (typeof id !== "string") {
19418 this.handleElId = id;
19419 this.DDM.regHandle(this.id, id);
19423 * Allows you to set an element outside of the linked element as a drag
19425 * @method setOuterHandleElId
19426 * @param id the id of the element that will be used to initiate the drag
19428 setOuterHandleElId: function(id) {
19429 if (typeof id !== "string") {
19432 Event.on(id, "mousedown",
19433 this.handleMouseDown, this);
19434 this.setHandleElId(id);
19436 this.hasOuterHandles = true;
19440 * Remove all drag and drop hooks for this element
19443 unreg: function() {
19444 Event.un(this.id, "mousedown",
19445 this.handleMouseDown);
19446 Event.un(this.id, "touchstart",
19447 this.handleMouseDown);
19448 this._domRef = null;
19449 this.DDM._remove(this);
19452 destroy : function(){
19457 * Returns true if this instance is locked, or the drag drop mgr is locked
19458 * (meaning that all drag/drop is disabled on the page.)
19460 * @return {boolean} true if this obj or all drag/drop is locked, else
19463 isLocked: function() {
19464 return (this.DDM.isLocked() || this.locked);
19468 * Fired when this object is clicked
19469 * @method handleMouseDown
19471 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19474 handleMouseDown: function(e, oDD){
19476 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19477 //Roo.log('not touch/ button !=0');
19480 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19481 return; // double touch..
19485 if (this.isLocked()) {
19486 //Roo.log('locked');
19490 this.DDM.refreshCache(this.groups);
19491 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19492 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19493 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19494 //Roo.log('no outer handes or not over target');
19497 // Roo.log('check validator');
19498 if (this.clickValidator(e)) {
19499 // Roo.log('validate success');
19500 // set the initial element position
19501 this.setStartPosition();
19504 this.b4MouseDown(e);
19505 this.onMouseDown(e);
19507 this.DDM.handleMouseDown(e, this);
19509 this.DDM.stopEvent(e);
19517 clickValidator: function(e) {
19518 var target = e.getTarget();
19519 return ( this.isValidHandleChild(target) &&
19520 (this.id == this.handleElId ||
19521 this.DDM.handleWasClicked(target, this.id)) );
19525 * Allows you to specify a tag name that should not start a drag operation
19526 * when clicked. This is designed to facilitate embedding links within a
19527 * drag handle that do something other than start the drag.
19528 * @method addInvalidHandleType
19529 * @param {string} tagName the type of element to exclude
19531 addInvalidHandleType: function(tagName) {
19532 var type = tagName.toUpperCase();
19533 this.invalidHandleTypes[type] = type;
19537 * Lets you to specify an element id for a child of a drag handle
19538 * that should not initiate a drag
19539 * @method addInvalidHandleId
19540 * @param {string} id the element id of the element you wish to ignore
19542 addInvalidHandleId: function(id) {
19543 if (typeof id !== "string") {
19546 this.invalidHandleIds[id] = id;
19550 * Lets you specify a css class of elements that will not initiate a drag
19551 * @method addInvalidHandleClass
19552 * @param {string} cssClass the class of the elements you wish to ignore
19554 addInvalidHandleClass: function(cssClass) {
19555 this.invalidHandleClasses.push(cssClass);
19559 * Unsets an excluded tag name set by addInvalidHandleType
19560 * @method removeInvalidHandleType
19561 * @param {string} tagName the type of element to unexclude
19563 removeInvalidHandleType: function(tagName) {
19564 var type = tagName.toUpperCase();
19565 // this.invalidHandleTypes[type] = null;
19566 delete this.invalidHandleTypes[type];
19570 * Unsets an invalid handle id
19571 * @method removeInvalidHandleId
19572 * @param {string} id the id of the element to re-enable
19574 removeInvalidHandleId: function(id) {
19575 if (typeof id !== "string") {
19578 delete this.invalidHandleIds[id];
19582 * Unsets an invalid css class
19583 * @method removeInvalidHandleClass
19584 * @param {string} cssClass the class of the element(s) you wish to
19587 removeInvalidHandleClass: function(cssClass) {
19588 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19589 if (this.invalidHandleClasses[i] == cssClass) {
19590 delete this.invalidHandleClasses[i];
19596 * Checks the tag exclusion list to see if this click should be ignored
19597 * @method isValidHandleChild
19598 * @param {HTMLElement} node the HTMLElement to evaluate
19599 * @return {boolean} true if this is a valid tag type, false if not
19601 isValidHandleChild: function(node) {
19604 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19607 nodeName = node.nodeName.toUpperCase();
19609 nodeName = node.nodeName;
19611 valid = valid && !this.invalidHandleTypes[nodeName];
19612 valid = valid && !this.invalidHandleIds[node.id];
19614 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19615 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19624 * Create the array of horizontal tick marks if an interval was specified
19625 * in setXConstraint().
19626 * @method setXTicks
19629 setXTicks: function(iStartX, iTickSize) {
19631 this.xTickSize = iTickSize;
19635 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19637 this.xTicks[this.xTicks.length] = i;
19642 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19644 this.xTicks[this.xTicks.length] = i;
19649 this.xTicks.sort(this.DDM.numericSort) ;
19653 * Create the array of vertical tick marks if an interval was specified in
19654 * setYConstraint().
19655 * @method setYTicks
19658 setYTicks: function(iStartY, iTickSize) {
19660 this.yTickSize = iTickSize;
19664 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19666 this.yTicks[this.yTicks.length] = i;
19671 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19673 this.yTicks[this.yTicks.length] = i;
19678 this.yTicks.sort(this.DDM.numericSort) ;
19682 * By default, the element can be dragged any place on the screen. Use
19683 * this method to limit the horizontal travel of the element. Pass in
19684 * 0,0 for the parameters if you want to lock the drag to the y axis.
19685 * @method setXConstraint
19686 * @param {int} iLeft the number of pixels the element can move to the left
19687 * @param {int} iRight the number of pixels the element can move to the
19689 * @param {int} iTickSize optional parameter for specifying that the
19691 * should move iTickSize pixels at a time.
19693 setXConstraint: function(iLeft, iRight, iTickSize) {
19694 this.leftConstraint = iLeft;
19695 this.rightConstraint = iRight;
19697 this.minX = this.initPageX - iLeft;
19698 this.maxX = this.initPageX + iRight;
19699 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19701 this.constrainX = true;
19705 * Clears any constraints applied to this instance. Also clears ticks
19706 * since they can't exist independent of a constraint at this time.
19707 * @method clearConstraints
19709 clearConstraints: function() {
19710 this.constrainX = false;
19711 this.constrainY = false;
19716 * Clears any tick interval defined for this instance
19717 * @method clearTicks
19719 clearTicks: function() {
19720 this.xTicks = null;
19721 this.yTicks = null;
19722 this.xTickSize = 0;
19723 this.yTickSize = 0;
19727 * By default, the element can be dragged any place on the screen. Set
19728 * this to limit the vertical travel of the element. Pass in 0,0 for the
19729 * parameters if you want to lock the drag to the x axis.
19730 * @method setYConstraint
19731 * @param {int} iUp the number of pixels the element can move up
19732 * @param {int} iDown the number of pixels the element can move down
19733 * @param {int} iTickSize optional parameter for specifying that the
19734 * element should move iTickSize pixels at a time.
19736 setYConstraint: function(iUp, iDown, iTickSize) {
19737 this.topConstraint = iUp;
19738 this.bottomConstraint = iDown;
19740 this.minY = this.initPageY - iUp;
19741 this.maxY = this.initPageY + iDown;
19742 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19744 this.constrainY = true;
19749 * resetConstraints must be called if you manually reposition a dd element.
19750 * @method resetConstraints
19751 * @param {boolean} maintainOffset
19753 resetConstraints: function() {
19756 // Maintain offsets if necessary
19757 if (this.initPageX || this.initPageX === 0) {
19758 // figure out how much this thing has moved
19759 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19760 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19762 this.setInitPosition(dx, dy);
19764 // This is the first time we have detected the element's position
19766 this.setInitPosition();
19769 if (this.constrainX) {
19770 this.setXConstraint( this.leftConstraint,
19771 this.rightConstraint,
19775 if (this.constrainY) {
19776 this.setYConstraint( this.topConstraint,
19777 this.bottomConstraint,
19783 * Normally the drag element is moved pixel by pixel, but we can specify
19784 * that it move a number of pixels at a time. This method resolves the
19785 * location when we have it set up like this.
19787 * @param {int} val where we want to place the object
19788 * @param {int[]} tickArray sorted array of valid points
19789 * @return {int} the closest tick
19792 getTick: function(val, tickArray) {
19795 // If tick interval is not defined, it is effectively 1 pixel,
19796 // so we return the value passed to us.
19798 } else if (tickArray[0] >= val) {
19799 // The value is lower than the first tick, so we return the first
19801 return tickArray[0];
19803 for (var i=0, len=tickArray.length; i<len; ++i) {
19805 if (tickArray[next] && tickArray[next] >= val) {
19806 var diff1 = val - tickArray[i];
19807 var diff2 = tickArray[next] - val;
19808 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19812 // The value is larger than the last tick, so we return the last
19814 return tickArray[tickArray.length - 1];
19821 * @return {string} string representation of the dd obj
19823 toString: function() {
19824 return ("DragDrop " + this.id);
19832 * Ext JS Library 1.1.1
19833 * Copyright(c) 2006-2007, Ext JS, LLC.
19835 * Originally Released Under LGPL - original licence link has changed is not relivant.
19838 * <script type="text/javascript">
19843 * The drag and drop utility provides a framework for building drag and drop
19844 * applications. In addition to enabling drag and drop for specific elements,
19845 * the drag and drop elements are tracked by the manager class, and the
19846 * interactions between the various elements are tracked during the drag and
19847 * the implementing code is notified about these important moments.
19850 // Only load the library once. Rewriting the manager class would orphan
19851 // existing drag and drop instances.
19852 if (!Roo.dd.DragDropMgr) {
19855 * @class Roo.dd.DragDropMgr
19856 * DragDropMgr is a singleton that tracks the element interaction for
19857 * all DragDrop items in the window. Generally, you will not call
19858 * this class directly, but it does have helper methods that could
19859 * be useful in your DragDrop implementations.
19862 Roo.dd.DragDropMgr = function() {
19864 var Event = Roo.EventManager;
19869 * Two dimensional Array of registered DragDrop objects. The first
19870 * dimension is the DragDrop item group, the second the DragDrop
19873 * @type {string: string}
19880 * Array of element ids defined as drag handles. Used to determine
19881 * if the element that generated the mousedown event is actually the
19882 * handle and not the html element itself.
19883 * @property handleIds
19884 * @type {string: string}
19891 * the DragDrop object that is currently being dragged
19892 * @property dragCurrent
19900 * the DragDrop object(s) that are being hovered over
19901 * @property dragOvers
19909 * the X distance between the cursor and the object being dragged
19918 * the Y distance between the cursor and the object being dragged
19927 * Flag to determine if we should prevent the default behavior of the
19928 * events we define. By default this is true, but this can be set to
19929 * false if you need the default behavior (not recommended)
19930 * @property preventDefault
19934 preventDefault: true,
19937 * Flag to determine if we should stop the propagation of the events
19938 * we generate. This is true by default but you may want to set it to
19939 * false if the html element contains other features that require the
19941 * @property stopPropagation
19945 stopPropagation: true,
19948 * Internal flag that is set to true when drag and drop has been
19950 * @property initialized
19957 * All drag and drop can be disabled.
19965 * Called the first time an element is registered.
19971 this.initialized = true;
19975 * In point mode, drag and drop interaction is defined by the
19976 * location of the cursor during the drag/drop
19984 * In intersect mode, drag and drop interactio nis defined by the
19985 * overlap of two or more drag and drop objects.
19986 * @property INTERSECT
19993 * The current drag and drop mode. Default: POINT
20001 * Runs method on all drag and drop objects
20002 * @method _execOnAll
20006 _execOnAll: function(sMethod, args) {
20007 for (var i in this.ids) {
20008 for (var j in this.ids[i]) {
20009 var oDD = this.ids[i][j];
20010 if (! this.isTypeOfDD(oDD)) {
20013 oDD[sMethod].apply(oDD, args);
20019 * Drag and drop initialization. Sets up the global event handlers
20024 _onLoad: function() {
20028 if (!Roo.isTouch) {
20029 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20030 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20032 Event.on(document, "touchend", this.handleMouseUp, this, true);
20033 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20035 Event.on(window, "unload", this._onUnload, this, true);
20036 Event.on(window, "resize", this._onResize, this, true);
20037 // Event.on(window, "mouseout", this._test);
20042 * Reset constraints on all drag and drop objs
20043 * @method _onResize
20047 _onResize: function(e) {
20048 this._execOnAll("resetConstraints", []);
20052 * Lock all drag and drop functionality
20056 lock: function() { this.locked = true; },
20059 * Unlock all drag and drop functionality
20063 unlock: function() { this.locked = false; },
20066 * Is drag and drop locked?
20068 * @return {boolean} True if drag and drop is locked, false otherwise.
20071 isLocked: function() { return this.locked; },
20074 * Location cache that is set for all drag drop objects when a drag is
20075 * initiated, cleared when the drag is finished.
20076 * @property locationCache
20083 * Set useCache to false if you want to force object the lookup of each
20084 * drag and drop linked element constantly during a drag.
20085 * @property useCache
20092 * The number of pixels that the mouse needs to move after the
20093 * mousedown before the drag is initiated. Default=3;
20094 * @property clickPixelThresh
20098 clickPixelThresh: 3,
20101 * The number of milliseconds after the mousedown event to initiate the
20102 * drag if we don't get a mouseup event. Default=1000
20103 * @property clickTimeThresh
20107 clickTimeThresh: 350,
20110 * Flag that indicates that either the drag pixel threshold or the
20111 * mousdown time threshold has been met
20112 * @property dragThreshMet
20117 dragThreshMet: false,
20120 * Timeout used for the click time threshold
20121 * @property clickTimeout
20126 clickTimeout: null,
20129 * The X position of the mousedown event stored for later use when a
20130 * drag threshold is met.
20139 * The Y position of the mousedown event stored for later use when a
20140 * drag threshold is met.
20149 * Each DragDrop instance must be registered with the DragDropMgr.
20150 * This is executed in DragDrop.init()
20151 * @method regDragDrop
20152 * @param {DragDrop} oDD the DragDrop object to register
20153 * @param {String} sGroup the name of the group this element belongs to
20156 regDragDrop: function(oDD, sGroup) {
20157 if (!this.initialized) { this.init(); }
20159 if (!this.ids[sGroup]) {
20160 this.ids[sGroup] = {};
20162 this.ids[sGroup][oDD.id] = oDD;
20166 * Removes the supplied dd instance from the supplied group. Executed
20167 * by DragDrop.removeFromGroup, so don't call this function directly.
20168 * @method removeDDFromGroup
20172 removeDDFromGroup: function(oDD, sGroup) {
20173 if (!this.ids[sGroup]) {
20174 this.ids[sGroup] = {};
20177 var obj = this.ids[sGroup];
20178 if (obj && obj[oDD.id]) {
20179 delete obj[oDD.id];
20184 * Unregisters a drag and drop item. This is executed in
20185 * DragDrop.unreg, use that method instead of calling this directly.
20190 _remove: function(oDD) {
20191 for (var g in oDD.groups) {
20192 if (g && this.ids[g][oDD.id]) {
20193 delete this.ids[g][oDD.id];
20196 delete this.handleIds[oDD.id];
20200 * Each DragDrop handle element must be registered. This is done
20201 * automatically when executing DragDrop.setHandleElId()
20202 * @method regHandle
20203 * @param {String} sDDId the DragDrop id this element is a handle for
20204 * @param {String} sHandleId the id of the element that is the drag
20208 regHandle: function(sDDId, sHandleId) {
20209 if (!this.handleIds[sDDId]) {
20210 this.handleIds[sDDId] = {};
20212 this.handleIds[sDDId][sHandleId] = sHandleId;
20216 * Utility function to determine if a given element has been
20217 * registered as a drag drop item.
20218 * @method isDragDrop
20219 * @param {String} id the element id to check
20220 * @return {boolean} true if this element is a DragDrop item,
20224 isDragDrop: function(id) {
20225 return ( this.getDDById(id) ) ? true : false;
20229 * Returns the drag and drop instances that are in all groups the
20230 * passed in instance belongs to.
20231 * @method getRelated
20232 * @param {DragDrop} p_oDD the obj to get related data for
20233 * @param {boolean} bTargetsOnly if true, only return targetable objs
20234 * @return {DragDrop[]} the related instances
20237 getRelated: function(p_oDD, bTargetsOnly) {
20239 for (var i in p_oDD.groups) {
20240 for (j in this.ids[i]) {
20241 var dd = this.ids[i][j];
20242 if (! this.isTypeOfDD(dd)) {
20245 if (!bTargetsOnly || dd.isTarget) {
20246 oDDs[oDDs.length] = dd;
20255 * Returns true if the specified dd target is a legal target for
20256 * the specifice drag obj
20257 * @method isLegalTarget
20258 * @param {DragDrop} the drag obj
20259 * @param {DragDrop} the target
20260 * @return {boolean} true if the target is a legal target for the
20264 isLegalTarget: function (oDD, oTargetDD) {
20265 var targets = this.getRelated(oDD, true);
20266 for (var i=0, len=targets.length;i<len;++i) {
20267 if (targets[i].id == oTargetDD.id) {
20276 * My goal is to be able to transparently determine if an object is
20277 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20278 * returns "object", oDD.constructor.toString() always returns
20279 * "DragDrop" and not the name of the subclass. So for now it just
20280 * evaluates a well-known variable in DragDrop.
20281 * @method isTypeOfDD
20282 * @param {Object} the object to evaluate
20283 * @return {boolean} true if typeof oDD = DragDrop
20286 isTypeOfDD: function (oDD) {
20287 return (oDD && oDD.__ygDragDrop);
20291 * Utility function to determine if a given element has been
20292 * registered as a drag drop handle for the given Drag Drop object.
20294 * @param {String} id the element id to check
20295 * @return {boolean} true if this element is a DragDrop handle, false
20299 isHandle: function(sDDId, sHandleId) {
20300 return ( this.handleIds[sDDId] &&
20301 this.handleIds[sDDId][sHandleId] );
20305 * Returns the DragDrop instance for a given id
20306 * @method getDDById
20307 * @param {String} id the id of the DragDrop object
20308 * @return {DragDrop} the drag drop object, null if it is not found
20311 getDDById: function(id) {
20312 for (var i in this.ids) {
20313 if (this.ids[i][id]) {
20314 return this.ids[i][id];
20321 * Fired after a registered DragDrop object gets the mousedown event.
20322 * Sets up the events required to track the object being dragged
20323 * @method handleMouseDown
20324 * @param {Event} e the event
20325 * @param oDD the DragDrop object being dragged
20329 handleMouseDown: function(e, oDD) {
20331 Roo.QuickTips.disable();
20333 this.currentTarget = e.getTarget();
20335 this.dragCurrent = oDD;
20337 var el = oDD.getEl();
20339 // track start position
20340 this.startX = e.getPageX();
20341 this.startY = e.getPageY();
20343 this.deltaX = this.startX - el.offsetLeft;
20344 this.deltaY = this.startY - el.offsetTop;
20346 this.dragThreshMet = false;
20348 this.clickTimeout = setTimeout(
20350 var DDM = Roo.dd.DDM;
20351 DDM.startDrag(DDM.startX, DDM.startY);
20353 this.clickTimeThresh );
20357 * Fired when either the drag pixel threshol or the mousedown hold
20358 * time threshold has been met.
20359 * @method startDrag
20360 * @param x {int} the X position of the original mousedown
20361 * @param y {int} the Y position of the original mousedown
20364 startDrag: function(x, y) {
20365 clearTimeout(this.clickTimeout);
20366 if (this.dragCurrent) {
20367 this.dragCurrent.b4StartDrag(x, y);
20368 this.dragCurrent.startDrag(x, y);
20370 this.dragThreshMet = true;
20374 * Internal function to handle the mouseup event. Will be invoked
20375 * from the context of the document.
20376 * @method handleMouseUp
20377 * @param {Event} e the event
20381 handleMouseUp: function(e) {
20384 Roo.QuickTips.enable();
20386 if (! this.dragCurrent) {
20390 clearTimeout(this.clickTimeout);
20392 if (this.dragThreshMet) {
20393 this.fireEvents(e, true);
20403 * Utility to stop event propagation and event default, if these
20404 * features are turned on.
20405 * @method stopEvent
20406 * @param {Event} e the event as returned by this.getEvent()
20409 stopEvent: function(e){
20410 if(this.stopPropagation) {
20411 e.stopPropagation();
20414 if (this.preventDefault) {
20415 e.preventDefault();
20420 * Internal function to clean up event handlers after the drag
20421 * operation is complete
20423 * @param {Event} e the event
20427 stopDrag: function(e) {
20428 // Fire the drag end event for the item that was dragged
20429 if (this.dragCurrent) {
20430 if (this.dragThreshMet) {
20431 this.dragCurrent.b4EndDrag(e);
20432 this.dragCurrent.endDrag(e);
20435 this.dragCurrent.onMouseUp(e);
20438 this.dragCurrent = null;
20439 this.dragOvers = {};
20443 * Internal function to handle the mousemove event. Will be invoked
20444 * from the context of the html element.
20446 * @TODO figure out what we can do about mouse events lost when the
20447 * user drags objects beyond the window boundary. Currently we can
20448 * detect this in internet explorer by verifying that the mouse is
20449 * down during the mousemove event. Firefox doesn't give us the
20450 * button state on the mousemove event.
20451 * @method handleMouseMove
20452 * @param {Event} e the event
20456 handleMouseMove: function(e) {
20457 if (! this.dragCurrent) {
20461 // var button = e.which || e.button;
20463 // check for IE mouseup outside of page boundary
20464 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20466 return this.handleMouseUp(e);
20469 if (!this.dragThreshMet) {
20470 var diffX = Math.abs(this.startX - e.getPageX());
20471 var diffY = Math.abs(this.startY - e.getPageY());
20472 if (diffX > this.clickPixelThresh ||
20473 diffY > this.clickPixelThresh) {
20474 this.startDrag(this.startX, this.startY);
20478 if (this.dragThreshMet) {
20479 this.dragCurrent.b4Drag(e);
20480 this.dragCurrent.onDrag(e);
20481 if(!this.dragCurrent.moveOnly){
20482 this.fireEvents(e, false);
20492 * Iterates over all of the DragDrop elements to find ones we are
20493 * hovering over or dropping on
20494 * @method fireEvents
20495 * @param {Event} e the event
20496 * @param {boolean} isDrop is this a drop op or a mouseover op?
20500 fireEvents: function(e, isDrop) {
20501 var dc = this.dragCurrent;
20503 // If the user did the mouse up outside of the window, we could
20504 // get here even though we have ended the drag.
20505 if (!dc || dc.isLocked()) {
20509 var pt = e.getPoint();
20511 // cache the previous dragOver array
20517 var enterEvts = [];
20519 // Check to see if the object(s) we were hovering over is no longer
20520 // being hovered over so we can fire the onDragOut event
20521 for (var i in this.dragOvers) {
20523 var ddo = this.dragOvers[i];
20525 if (! this.isTypeOfDD(ddo)) {
20529 if (! this.isOverTarget(pt, ddo, this.mode)) {
20530 outEvts.push( ddo );
20533 oldOvers[i] = true;
20534 delete this.dragOvers[i];
20537 for (var sGroup in dc.groups) {
20539 if ("string" != typeof sGroup) {
20543 for (i in this.ids[sGroup]) {
20544 var oDD = this.ids[sGroup][i];
20545 if (! this.isTypeOfDD(oDD)) {
20549 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20550 if (this.isOverTarget(pt, oDD, this.mode)) {
20551 // look for drop interactions
20553 dropEvts.push( oDD );
20554 // look for drag enter and drag over interactions
20557 // initial drag over: dragEnter fires
20558 if (!oldOvers[oDD.id]) {
20559 enterEvts.push( oDD );
20560 // subsequent drag overs: dragOver fires
20562 overEvts.push( oDD );
20565 this.dragOvers[oDD.id] = oDD;
20573 if (outEvts.length) {
20574 dc.b4DragOut(e, outEvts);
20575 dc.onDragOut(e, outEvts);
20578 if (enterEvts.length) {
20579 dc.onDragEnter(e, enterEvts);
20582 if (overEvts.length) {
20583 dc.b4DragOver(e, overEvts);
20584 dc.onDragOver(e, overEvts);
20587 if (dropEvts.length) {
20588 dc.b4DragDrop(e, dropEvts);
20589 dc.onDragDrop(e, dropEvts);
20593 // fire dragout events
20595 for (i=0, len=outEvts.length; i<len; ++i) {
20596 dc.b4DragOut(e, outEvts[i].id);
20597 dc.onDragOut(e, outEvts[i].id);
20600 // fire enter events
20601 for (i=0,len=enterEvts.length; i<len; ++i) {
20602 // dc.b4DragEnter(e, oDD.id);
20603 dc.onDragEnter(e, enterEvts[i].id);
20606 // fire over events
20607 for (i=0,len=overEvts.length; i<len; ++i) {
20608 dc.b4DragOver(e, overEvts[i].id);
20609 dc.onDragOver(e, overEvts[i].id);
20612 // fire drop events
20613 for (i=0, len=dropEvts.length; i<len; ++i) {
20614 dc.b4DragDrop(e, dropEvts[i].id);
20615 dc.onDragDrop(e, dropEvts[i].id);
20620 // notify about a drop that did not find a target
20621 if (isDrop && !dropEvts.length) {
20622 dc.onInvalidDrop(e);
20628 * Helper function for getting the best match from the list of drag
20629 * and drop objects returned by the drag and drop events when we are
20630 * in INTERSECT mode. It returns either the first object that the
20631 * cursor is over, or the object that has the greatest overlap with
20632 * the dragged element.
20633 * @method getBestMatch
20634 * @param {DragDrop[]} dds The array of drag and drop objects
20636 * @return {DragDrop} The best single match
20639 getBestMatch: function(dds) {
20641 // Return null if the input is not what we expect
20642 //if (!dds || !dds.length || dds.length == 0) {
20644 // If there is only one item, it wins
20645 //} else if (dds.length == 1) {
20647 var len = dds.length;
20652 // Loop through the targeted items
20653 for (var i=0; i<len; ++i) {
20655 // If the cursor is over the object, it wins. If the
20656 // cursor is over multiple matches, the first one we come
20658 if (dd.cursorIsOver) {
20661 // Otherwise the object with the most overlap wins
20664 winner.overlap.getArea() < dd.overlap.getArea()) {
20675 * Refreshes the cache of the top-left and bottom-right points of the
20676 * drag and drop objects in the specified group(s). This is in the
20677 * format that is stored in the drag and drop instance, so typical
20680 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20684 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20686 * @TODO this really should be an indexed array. Alternatively this
20687 * method could accept both.
20688 * @method refreshCache
20689 * @param {Object} groups an associative array of groups to refresh
20692 refreshCache: function(groups) {
20693 for (var sGroup in groups) {
20694 if ("string" != typeof sGroup) {
20697 for (var i in this.ids[sGroup]) {
20698 var oDD = this.ids[sGroup][i];
20700 if (this.isTypeOfDD(oDD)) {
20701 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20702 var loc = this.getLocation(oDD);
20704 this.locationCache[oDD.id] = loc;
20706 delete this.locationCache[oDD.id];
20707 // this will unregister the drag and drop object if
20708 // the element is not in a usable state
20717 * This checks to make sure an element exists and is in the DOM. The
20718 * main purpose is to handle cases where innerHTML is used to remove
20719 * drag and drop objects from the DOM. IE provides an 'unspecified
20720 * error' when trying to access the offsetParent of such an element
20722 * @param {HTMLElement} el the element to check
20723 * @return {boolean} true if the element looks usable
20726 verifyEl: function(el) {
20731 parent = el.offsetParent;
20734 parent = el.offsetParent;
20745 * Returns a Region object containing the drag and drop element's position
20746 * and size, including the padding configured for it
20747 * @method getLocation
20748 * @param {DragDrop} oDD the drag and drop object to get the
20750 * @return {Roo.lib.Region} a Region object representing the total area
20751 * the element occupies, including any padding
20752 * the instance is configured for.
20755 getLocation: function(oDD) {
20756 if (! this.isTypeOfDD(oDD)) {
20760 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20763 pos= Roo.lib.Dom.getXY(el);
20771 x2 = x1 + el.offsetWidth;
20773 y2 = y1 + el.offsetHeight;
20775 t = y1 - oDD.padding[0];
20776 r = x2 + oDD.padding[1];
20777 b = y2 + oDD.padding[2];
20778 l = x1 - oDD.padding[3];
20780 return new Roo.lib.Region( t, r, b, l );
20784 * Checks the cursor location to see if it over the target
20785 * @method isOverTarget
20786 * @param {Roo.lib.Point} pt The point to evaluate
20787 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20788 * @return {boolean} true if the mouse is over the target
20792 isOverTarget: function(pt, oTarget, intersect) {
20793 // use cache if available
20794 var loc = this.locationCache[oTarget.id];
20795 if (!loc || !this.useCache) {
20796 loc = this.getLocation(oTarget);
20797 this.locationCache[oTarget.id] = loc;
20805 oTarget.cursorIsOver = loc.contains( pt );
20807 // DragDrop is using this as a sanity check for the initial mousedown
20808 // in this case we are done. In POINT mode, if the drag obj has no
20809 // contraints, we are also done. Otherwise we need to evaluate the
20810 // location of the target as related to the actual location of the
20811 // dragged element.
20812 var dc = this.dragCurrent;
20813 if (!dc || !dc.getTargetCoord ||
20814 (!intersect && !dc.constrainX && !dc.constrainY)) {
20815 return oTarget.cursorIsOver;
20818 oTarget.overlap = null;
20820 // Get the current location of the drag element, this is the
20821 // location of the mouse event less the delta that represents
20822 // where the original mousedown happened on the element. We
20823 // need to consider constraints and ticks as well.
20824 var pos = dc.getTargetCoord(pt.x, pt.y);
20826 var el = dc.getDragEl();
20827 var curRegion = new Roo.lib.Region( pos.y,
20828 pos.x + el.offsetWidth,
20829 pos.y + el.offsetHeight,
20832 var overlap = curRegion.intersect(loc);
20835 oTarget.overlap = overlap;
20836 return (intersect) ? true : oTarget.cursorIsOver;
20843 * unload event handler
20844 * @method _onUnload
20848 _onUnload: function(e, me) {
20849 Roo.dd.DragDropMgr.unregAll();
20853 * Cleans up the drag and drop events and objects.
20858 unregAll: function() {
20860 if (this.dragCurrent) {
20862 this.dragCurrent = null;
20865 this._execOnAll("unreg", []);
20867 for (i in this.elementCache) {
20868 delete this.elementCache[i];
20871 this.elementCache = {};
20876 * A cache of DOM elements
20877 * @property elementCache
20884 * Get the wrapper for the DOM element specified
20885 * @method getElWrapper
20886 * @param {String} id the id of the element to get
20887 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20889 * @deprecated This wrapper isn't that useful
20892 getElWrapper: function(id) {
20893 var oWrapper = this.elementCache[id];
20894 if (!oWrapper || !oWrapper.el) {
20895 oWrapper = this.elementCache[id] =
20896 new this.ElementWrapper(Roo.getDom(id));
20902 * Returns the actual DOM element
20903 * @method getElement
20904 * @param {String} id the id of the elment to get
20905 * @return {Object} The element
20906 * @deprecated use Roo.getDom instead
20909 getElement: function(id) {
20910 return Roo.getDom(id);
20914 * Returns the style property for the DOM element (i.e.,
20915 * document.getElById(id).style)
20917 * @param {String} id the id of the elment to get
20918 * @return {Object} The style property of the element
20919 * @deprecated use Roo.getDom instead
20922 getCss: function(id) {
20923 var el = Roo.getDom(id);
20924 return (el) ? el.style : null;
20928 * Inner class for cached elements
20929 * @class DragDropMgr.ElementWrapper
20934 ElementWrapper: function(el) {
20939 this.el = el || null;
20944 this.id = this.el && el.id;
20946 * A reference to the style property
20949 this.css = this.el && el.style;
20953 * Returns the X position of an html element
20955 * @param el the element for which to get the position
20956 * @return {int} the X coordinate
20958 * @deprecated use Roo.lib.Dom.getX instead
20961 getPosX: function(el) {
20962 return Roo.lib.Dom.getX(el);
20966 * Returns the Y position of an html element
20968 * @param el the element for which to get the position
20969 * @return {int} the Y coordinate
20970 * @deprecated use Roo.lib.Dom.getY instead
20973 getPosY: function(el) {
20974 return Roo.lib.Dom.getY(el);
20978 * Swap two nodes. In IE, we use the native method, for others we
20979 * emulate the IE behavior
20981 * @param n1 the first node to swap
20982 * @param n2 the other node to swap
20985 swapNode: function(n1, n2) {
20989 var p = n2.parentNode;
20990 var s = n2.nextSibling;
20993 p.insertBefore(n1, n2);
20994 } else if (n2 == n1.nextSibling) {
20995 p.insertBefore(n2, n1);
20997 n1.parentNode.replaceChild(n2, n1);
20998 p.insertBefore(n1, s);
21004 * Returns the current scroll position
21005 * @method getScroll
21009 getScroll: function () {
21010 var t, l, dde=document.documentElement, db=document.body;
21011 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21013 l = dde.scrollLeft;
21020 return { top: t, left: l };
21024 * Returns the specified element style property
21026 * @param {HTMLElement} el the element
21027 * @param {string} styleProp the style property
21028 * @return {string} The value of the style property
21029 * @deprecated use Roo.lib.Dom.getStyle
21032 getStyle: function(el, styleProp) {
21033 return Roo.fly(el).getStyle(styleProp);
21037 * Gets the scrollTop
21038 * @method getScrollTop
21039 * @return {int} the document's scrollTop
21042 getScrollTop: function () { return this.getScroll().top; },
21045 * Gets the scrollLeft
21046 * @method getScrollLeft
21047 * @return {int} the document's scrollTop
21050 getScrollLeft: function () { return this.getScroll().left; },
21053 * Sets the x/y position of an element to the location of the
21056 * @param {HTMLElement} moveEl The element to move
21057 * @param {HTMLElement} targetEl The position reference element
21060 moveToEl: function (moveEl, targetEl) {
21061 var aCoord = Roo.lib.Dom.getXY(targetEl);
21062 Roo.lib.Dom.setXY(moveEl, aCoord);
21066 * Numeric array sort function
21067 * @method numericSort
21070 numericSort: function(a, b) { return (a - b); },
21074 * @property _timeoutCount
21081 * Trying to make the load order less important. Without this we get
21082 * an error if this file is loaded before the Event Utility.
21083 * @method _addListeners
21087 _addListeners: function() {
21088 var DDM = Roo.dd.DDM;
21089 if ( Roo.lib.Event && document ) {
21092 if (DDM._timeoutCount > 2000) {
21094 setTimeout(DDM._addListeners, 10);
21095 if (document && document.body) {
21096 DDM._timeoutCount += 1;
21103 * Recursively searches the immediate parent and all child nodes for
21104 * the handle element in order to determine wheter or not it was
21106 * @method handleWasClicked
21107 * @param node the html element to inspect
21110 handleWasClicked: function(node, id) {
21111 if (this.isHandle(id, node.id)) {
21114 // check to see if this is a text node child of the one we want
21115 var p = node.parentNode;
21118 if (this.isHandle(id, p.id)) {
21133 // shorter alias, save a few bytes
21134 Roo.dd.DDM = Roo.dd.DragDropMgr;
21135 Roo.dd.DDM._addListeners();
21139 * Ext JS Library 1.1.1
21140 * Copyright(c) 2006-2007, Ext JS, LLC.
21142 * Originally Released Under LGPL - original licence link has changed is not relivant.
21145 * <script type="text/javascript">
21150 * A DragDrop implementation where the linked element follows the
21151 * mouse cursor during a drag.
21152 * @extends Roo.dd.DragDrop
21154 * @param {String} id the id of the linked element
21155 * @param {String} sGroup the group of related DragDrop items
21156 * @param {object} config an object containing configurable attributes
21157 * Valid properties for DD:
21160 Roo.dd.DD = function(id, sGroup, config) {
21162 this.init(id, sGroup, config);
21166 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21169 * When set to true, the utility automatically tries to scroll the browser
21170 * window wehn a drag and drop element is dragged near the viewport boundary.
21171 * Defaults to true.
21178 * Sets the pointer offset to the distance between the linked element's top
21179 * left corner and the location the element was clicked
21180 * @method autoOffset
21181 * @param {int} iPageX the X coordinate of the click
21182 * @param {int} iPageY the Y coordinate of the click
21184 autoOffset: function(iPageX, iPageY) {
21185 var x = iPageX - this.startPageX;
21186 var y = iPageY - this.startPageY;
21187 this.setDelta(x, y);
21191 * Sets the pointer offset. You can call this directly to force the
21192 * offset to be in a particular location (e.g., pass in 0,0 to set it
21193 * to the center of the object)
21195 * @param {int} iDeltaX the distance from the left
21196 * @param {int} iDeltaY the distance from the top
21198 setDelta: function(iDeltaX, iDeltaY) {
21199 this.deltaX = iDeltaX;
21200 this.deltaY = iDeltaY;
21204 * Sets the drag element to the location of the mousedown or click event,
21205 * maintaining the cursor location relative to the location on the element
21206 * that was clicked. Override this if you want to place the element in a
21207 * location other than where the cursor is.
21208 * @method setDragElPos
21209 * @param {int} iPageX the X coordinate of the mousedown or drag event
21210 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21212 setDragElPos: function(iPageX, iPageY) {
21213 // the first time we do this, we are going to check to make sure
21214 // the element has css positioning
21216 var el = this.getDragEl();
21217 this.alignElWithMouse(el, iPageX, iPageY);
21221 * Sets the element to the location of the mousedown or click event,
21222 * maintaining the cursor location relative to the location on the element
21223 * that was clicked. Override this if you want to place the element in a
21224 * location other than where the cursor is.
21225 * @method alignElWithMouse
21226 * @param {HTMLElement} el the element to move
21227 * @param {int} iPageX the X coordinate of the mousedown or drag event
21228 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21230 alignElWithMouse: function(el, iPageX, iPageY) {
21231 var oCoord = this.getTargetCoord(iPageX, iPageY);
21232 var fly = el.dom ? el : Roo.fly(el);
21233 if (!this.deltaSetXY) {
21234 var aCoord = [oCoord.x, oCoord.y];
21236 var newLeft = fly.getLeft(true);
21237 var newTop = fly.getTop(true);
21238 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21240 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21243 this.cachePosition(oCoord.x, oCoord.y);
21244 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21249 * Saves the most recent position so that we can reset the constraints and
21250 * tick marks on-demand. We need to know this so that we can calculate the
21251 * number of pixels the element is offset from its original position.
21252 * @method cachePosition
21253 * @param iPageX the current x position (optional, this just makes it so we
21254 * don't have to look it up again)
21255 * @param iPageY the current y position (optional, this just makes it so we
21256 * don't have to look it up again)
21258 cachePosition: function(iPageX, iPageY) {
21260 this.lastPageX = iPageX;
21261 this.lastPageY = iPageY;
21263 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21264 this.lastPageX = aCoord[0];
21265 this.lastPageY = aCoord[1];
21270 * Auto-scroll the window if the dragged object has been moved beyond the
21271 * visible window boundary.
21272 * @method autoScroll
21273 * @param {int} x the drag element's x position
21274 * @param {int} y the drag element's y position
21275 * @param {int} h the height of the drag element
21276 * @param {int} w the width of the drag element
21279 autoScroll: function(x, y, h, w) {
21282 // The client height
21283 var clientH = Roo.lib.Dom.getViewWidth();
21285 // The client width
21286 var clientW = Roo.lib.Dom.getViewHeight();
21288 // The amt scrolled down
21289 var st = this.DDM.getScrollTop();
21291 // The amt scrolled right
21292 var sl = this.DDM.getScrollLeft();
21294 // Location of the bottom of the element
21297 // Location of the right of the element
21300 // The distance from the cursor to the bottom of the visible area,
21301 // adjusted so that we don't scroll if the cursor is beyond the
21302 // element drag constraints
21303 var toBot = (clientH + st - y - this.deltaY);
21305 // The distance from the cursor to the right of the visible area
21306 var toRight = (clientW + sl - x - this.deltaX);
21309 // How close to the edge the cursor must be before we scroll
21310 // var thresh = (document.all) ? 100 : 40;
21313 // How many pixels to scroll per autoscroll op. This helps to reduce
21314 // clunky scrolling. IE is more sensitive about this ... it needs this
21315 // value to be higher.
21316 var scrAmt = (document.all) ? 80 : 30;
21318 // Scroll down if we are near the bottom of the visible page and the
21319 // obj extends below the crease
21320 if ( bot > clientH && toBot < thresh ) {
21321 window.scrollTo(sl, st + scrAmt);
21324 // Scroll up if the window is scrolled down and the top of the object
21325 // goes above the top border
21326 if ( y < st && st > 0 && y - st < thresh ) {
21327 window.scrollTo(sl, st - scrAmt);
21330 // Scroll right if the obj is beyond the right border and the cursor is
21331 // near the border.
21332 if ( right > clientW && toRight < thresh ) {
21333 window.scrollTo(sl + scrAmt, st);
21336 // Scroll left if the window has been scrolled to the right and the obj
21337 // extends past the left border
21338 if ( x < sl && sl > 0 && x - sl < thresh ) {
21339 window.scrollTo(sl - scrAmt, st);
21345 * Finds the location the element should be placed if we want to move
21346 * it to where the mouse location less the click offset would place us.
21347 * @method getTargetCoord
21348 * @param {int} iPageX the X coordinate of the click
21349 * @param {int} iPageY the Y coordinate of the click
21350 * @return an object that contains the coordinates (Object.x and Object.y)
21353 getTargetCoord: function(iPageX, iPageY) {
21356 var x = iPageX - this.deltaX;
21357 var y = iPageY - this.deltaY;
21359 if (this.constrainX) {
21360 if (x < this.minX) { x = this.minX; }
21361 if (x > this.maxX) { x = this.maxX; }
21364 if (this.constrainY) {
21365 if (y < this.minY) { y = this.minY; }
21366 if (y > this.maxY) { y = this.maxY; }
21369 x = this.getTick(x, this.xTicks);
21370 y = this.getTick(y, this.yTicks);
21377 * Sets up config options specific to this class. Overrides
21378 * Roo.dd.DragDrop, but all versions of this method through the
21379 * inheritance chain are called
21381 applyConfig: function() {
21382 Roo.dd.DD.superclass.applyConfig.call(this);
21383 this.scroll = (this.config.scroll !== false);
21387 * Event that fires prior to the onMouseDown event. Overrides
21390 b4MouseDown: function(e) {
21391 // this.resetConstraints();
21392 this.autoOffset(e.getPageX(),
21397 * Event that fires prior to the onDrag event. Overrides
21400 b4Drag: function(e) {
21401 this.setDragElPos(e.getPageX(),
21405 toString: function() {
21406 return ("DD " + this.id);
21409 //////////////////////////////////////////////////////////////////////////
21410 // Debugging ygDragDrop events that can be overridden
21411 //////////////////////////////////////////////////////////////////////////
21413 startDrag: function(x, y) {
21416 onDrag: function(e) {
21419 onDragEnter: function(e, id) {
21422 onDragOver: function(e, id) {
21425 onDragOut: function(e, id) {
21428 onDragDrop: function(e, id) {
21431 endDrag: function(e) {
21438 * Ext JS Library 1.1.1
21439 * Copyright(c) 2006-2007, Ext JS, LLC.
21441 * Originally Released Under LGPL - original licence link has changed is not relivant.
21444 * <script type="text/javascript">
21448 * @class Roo.dd.DDProxy
21449 * A DragDrop implementation that inserts an empty, bordered div into
21450 * the document that follows the cursor during drag operations. At the time of
21451 * the click, the frame div is resized to the dimensions of the linked html
21452 * element, and moved to the exact location of the linked element.
21454 * References to the "frame" element refer to the single proxy element that
21455 * was created to be dragged in place of all DDProxy elements on the
21458 * @extends Roo.dd.DD
21460 * @param {String} id the id of the linked html element
21461 * @param {String} sGroup the group of related DragDrop objects
21462 * @param {object} config an object containing configurable attributes
21463 * Valid properties for DDProxy in addition to those in DragDrop:
21464 * resizeFrame, centerFrame, dragElId
21466 Roo.dd.DDProxy = function(id, sGroup, config) {
21468 this.init(id, sGroup, config);
21474 * The default drag frame div id
21475 * @property Roo.dd.DDProxy.dragElId
21479 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21481 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21484 * By default we resize the drag frame to be the same size as the element
21485 * we want to drag (this is to get the frame effect). We can turn it off
21486 * if we want a different behavior.
21487 * @property resizeFrame
21493 * By default the frame is positioned exactly where the drag element is, so
21494 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21495 * you do not have constraints on the obj is to have the drag frame centered
21496 * around the cursor. Set centerFrame to true for this effect.
21497 * @property centerFrame
21500 centerFrame: false,
21503 * Creates the proxy element if it does not yet exist
21504 * @method createFrame
21506 createFrame: function() {
21508 var body = document.body;
21510 if (!body || !body.firstChild) {
21511 setTimeout( function() { self.createFrame(); }, 50 );
21515 var div = this.getDragEl();
21518 div = document.createElement("div");
21519 div.id = this.dragElId;
21522 s.position = "absolute";
21523 s.visibility = "hidden";
21525 s.border = "2px solid #aaa";
21528 // appendChild can blow up IE if invoked prior to the window load event
21529 // while rendering a table. It is possible there are other scenarios
21530 // that would cause this to happen as well.
21531 body.insertBefore(div, body.firstChild);
21536 * Initialization for the drag frame element. Must be called in the
21537 * constructor of all subclasses
21538 * @method initFrame
21540 initFrame: function() {
21541 this.createFrame();
21544 applyConfig: function() {
21545 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21547 this.resizeFrame = (this.config.resizeFrame !== false);
21548 this.centerFrame = (this.config.centerFrame);
21549 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21553 * Resizes the drag frame to the dimensions of the clicked object, positions
21554 * it over the object, and finally displays it
21555 * @method showFrame
21556 * @param {int} iPageX X click position
21557 * @param {int} iPageY Y click position
21560 showFrame: function(iPageX, iPageY) {
21561 var el = this.getEl();
21562 var dragEl = this.getDragEl();
21563 var s = dragEl.style;
21565 this._resizeProxy();
21567 if (this.centerFrame) {
21568 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21569 Math.round(parseInt(s.height, 10)/2) );
21572 this.setDragElPos(iPageX, iPageY);
21574 Roo.fly(dragEl).show();
21578 * The proxy is automatically resized to the dimensions of the linked
21579 * element when a drag is initiated, unless resizeFrame is set to false
21580 * @method _resizeProxy
21583 _resizeProxy: function() {
21584 if (this.resizeFrame) {
21585 var el = this.getEl();
21586 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21590 // overrides Roo.dd.DragDrop
21591 b4MouseDown: function(e) {
21592 var x = e.getPageX();
21593 var y = e.getPageY();
21594 this.autoOffset(x, y);
21595 this.setDragElPos(x, y);
21598 // overrides Roo.dd.DragDrop
21599 b4StartDrag: function(x, y) {
21600 // show the drag frame
21601 this.showFrame(x, y);
21604 // overrides Roo.dd.DragDrop
21605 b4EndDrag: function(e) {
21606 Roo.fly(this.getDragEl()).hide();
21609 // overrides Roo.dd.DragDrop
21610 // By default we try to move the element to the last location of the frame.
21611 // This is so that the default behavior mirrors that of Roo.dd.DD.
21612 endDrag: function(e) {
21614 var lel = this.getEl();
21615 var del = this.getDragEl();
21617 // Show the drag frame briefly so we can get its position
21618 del.style.visibility = "";
21621 // Hide the linked element before the move to get around a Safari
21623 lel.style.visibility = "hidden";
21624 Roo.dd.DDM.moveToEl(lel, del);
21625 del.style.visibility = "hidden";
21626 lel.style.visibility = "";
21631 beforeMove : function(){
21635 afterDrag : function(){
21639 toString: function() {
21640 return ("DDProxy " + this.id);
21646 * Ext JS Library 1.1.1
21647 * Copyright(c) 2006-2007, Ext JS, LLC.
21649 * Originally Released Under LGPL - original licence link has changed is not relivant.
21652 * <script type="text/javascript">
21656 * @class Roo.dd.DDTarget
21657 * A DragDrop implementation that does not move, but can be a drop
21658 * target. You would get the same result by simply omitting implementation
21659 * for the event callbacks, but this way we reduce the processing cost of the
21660 * event listener and the callbacks.
21661 * @extends Roo.dd.DragDrop
21663 * @param {String} id the id of the element that is a drop target
21664 * @param {String} sGroup the group of related DragDrop objects
21665 * @param {object} config an object containing configurable attributes
21666 * Valid properties for DDTarget in addition to those in
21670 Roo.dd.DDTarget = function(id, sGroup, config) {
21672 this.initTarget(id, sGroup, config);
21674 if (config && (config.listeners || config.events)) {
21675 Roo.dd.DragDrop.superclass.constructor.call(this, {
21676 listeners : config.listeners || {},
21677 events : config.events || {}
21682 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21683 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21684 toString: function() {
21685 return ("DDTarget " + this.id);
21690 * Ext JS Library 1.1.1
21691 * Copyright(c) 2006-2007, Ext JS, LLC.
21693 * Originally Released Under LGPL - original licence link has changed is not relivant.
21696 * <script type="text/javascript">
21701 * @class Roo.dd.ScrollManager
21702 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21703 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21706 Roo.dd.ScrollManager = function(){
21707 var ddm = Roo.dd.DragDropMgr;
21714 var onStop = function(e){
21719 var triggerRefresh = function(){
21720 if(ddm.dragCurrent){
21721 ddm.refreshCache(ddm.dragCurrent.groups);
21725 var doScroll = function(){
21726 if(ddm.dragCurrent){
21727 var dds = Roo.dd.ScrollManager;
21729 if(proc.el.scroll(proc.dir, dds.increment)){
21733 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21738 var clearProc = function(){
21740 clearInterval(proc.id);
21747 var startProc = function(el, dir){
21748 Roo.log('scroll startproc');
21752 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21755 var onFire = function(e, isDrop){
21757 if(isDrop || !ddm.dragCurrent){ return; }
21758 var dds = Roo.dd.ScrollManager;
21759 if(!dragEl || dragEl != ddm.dragCurrent){
21760 dragEl = ddm.dragCurrent;
21761 // refresh regions on drag start
21762 dds.refreshCache();
21765 var xy = Roo.lib.Event.getXY(e);
21766 var pt = new Roo.lib.Point(xy[0], xy[1]);
21767 for(var id in els){
21768 var el = els[id], r = el._region;
21769 if(r && r.contains(pt) && el.isScrollable()){
21770 if(r.bottom - pt.y <= dds.thresh){
21772 startProc(el, "down");
21775 }else if(r.right - pt.x <= dds.thresh){
21777 startProc(el, "left");
21780 }else if(pt.y - r.top <= dds.thresh){
21782 startProc(el, "up");
21785 }else if(pt.x - r.left <= dds.thresh){
21787 startProc(el, "right");
21796 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21797 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21801 * Registers new overflow element(s) to auto scroll
21802 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21804 register : function(el){
21805 if(el instanceof Array){
21806 for(var i = 0, len = el.length; i < len; i++) {
21807 this.register(el[i]);
21813 Roo.dd.ScrollManager.els = els;
21817 * Unregisters overflow element(s) so they are no longer scrolled
21818 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21820 unregister : function(el){
21821 if(el instanceof Array){
21822 for(var i = 0, len = el.length; i < len; i++) {
21823 this.unregister(el[i]);
21832 * The number of pixels from the edge of a container the pointer needs to be to
21833 * trigger scrolling (defaults to 25)
21839 * The number of pixels to scroll in each scroll increment (defaults to 50)
21845 * The frequency of scrolls in milliseconds (defaults to 500)
21851 * True to animate the scroll (defaults to true)
21857 * The animation duration in seconds -
21858 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21864 * Manually trigger a cache refresh.
21866 refreshCache : function(){
21867 for(var id in els){
21868 if(typeof els[id] == 'object'){ // for people extending the object prototype
21869 els[id]._region = els[id].getRegion();
21876 * Ext JS Library 1.1.1
21877 * Copyright(c) 2006-2007, Ext JS, LLC.
21879 * Originally Released Under LGPL - original licence link has changed is not relivant.
21882 * <script type="text/javascript">
21887 * @class Roo.dd.Registry
21888 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21889 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21892 Roo.dd.Registry = function(){
21895 var autoIdSeed = 0;
21897 var getId = function(el, autogen){
21898 if(typeof el == "string"){
21902 if(!id && autogen !== false){
21903 id = "roodd-" + (++autoIdSeed);
21911 * Register a drag drop element
21912 * @param {String|HTMLElement} element The id or DOM node to register
21913 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21914 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21915 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21916 * populated in the data object (if applicable):
21918 Value Description<br />
21919 --------- ------------------------------------------<br />
21920 handles Array of DOM nodes that trigger dragging<br />
21921 for the element being registered<br />
21922 isHandle True if the element passed in triggers<br />
21923 dragging itself, else false
21926 register : function(el, data){
21928 if(typeof el == "string"){
21929 el = document.getElementById(el);
21932 elements[getId(el)] = data;
21933 if(data.isHandle !== false){
21934 handles[data.ddel.id] = data;
21937 var hs = data.handles;
21938 for(var i = 0, len = hs.length; i < len; i++){
21939 handles[getId(hs[i])] = data;
21945 * Unregister a drag drop element
21946 * @param {String|HTMLElement} element The id or DOM node to unregister
21948 unregister : function(el){
21949 var id = getId(el, false);
21950 var data = elements[id];
21952 delete elements[id];
21954 var hs = data.handles;
21955 for(var i = 0, len = hs.length; i < len; i++){
21956 delete handles[getId(hs[i], false)];
21963 * Returns the handle registered for a DOM Node by id
21964 * @param {String|HTMLElement} id The DOM node or id to look up
21965 * @return {Object} handle The custom handle data
21967 getHandle : function(id){
21968 if(typeof id != "string"){ // must be element?
21971 return handles[id];
21975 * Returns the handle that is registered for the DOM node that is the target of the event
21976 * @param {Event} e The event
21977 * @return {Object} handle The custom handle data
21979 getHandleFromEvent : function(e){
21980 var t = Roo.lib.Event.getTarget(e);
21981 return t ? handles[t.id] : null;
21985 * Returns a custom data object that is registered for a DOM node by id
21986 * @param {String|HTMLElement} id The DOM node or id to look up
21987 * @return {Object} data The custom data
21989 getTarget : function(id){
21990 if(typeof id != "string"){ // must be element?
21993 return elements[id];
21997 * Returns a custom data object that is registered for the DOM node that is the target of the event
21998 * @param {Event} e The event
21999 * @return {Object} data The custom data
22001 getTargetFromEvent : function(e){
22002 var t = Roo.lib.Event.getTarget(e);
22003 return t ? elements[t.id] || handles[t.id] : null;
22008 * Ext JS Library 1.1.1
22009 * Copyright(c) 2006-2007, Ext JS, LLC.
22011 * Originally Released Under LGPL - original licence link has changed is not relivant.
22014 * <script type="text/javascript">
22019 * @class Roo.dd.StatusProxy
22020 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22021 * default drag proxy used by all Roo.dd components.
22023 * @param {Object} config
22025 Roo.dd.StatusProxy = function(config){
22026 Roo.apply(this, config);
22027 this.id = this.id || Roo.id();
22028 this.el = new Roo.Layer({
22030 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22031 {tag: "div", cls: "x-dd-drop-icon"},
22032 {tag: "div", cls: "x-dd-drag-ghost"}
22035 shadow: !config || config.shadow !== false
22037 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22038 this.dropStatus = this.dropNotAllowed;
22041 Roo.dd.StatusProxy.prototype = {
22043 * @cfg {String} dropAllowed
22044 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22046 dropAllowed : "x-dd-drop-ok",
22048 * @cfg {String} dropNotAllowed
22049 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22051 dropNotAllowed : "x-dd-drop-nodrop",
22054 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22055 * over the current target element.
22056 * @param {String} cssClass The css class for the new drop status indicator image
22058 setStatus : function(cssClass){
22059 cssClass = cssClass || this.dropNotAllowed;
22060 if(this.dropStatus != cssClass){
22061 this.el.replaceClass(this.dropStatus, cssClass);
22062 this.dropStatus = cssClass;
22067 * Resets the status indicator to the default dropNotAllowed value
22068 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22070 reset : function(clearGhost){
22071 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22072 this.dropStatus = this.dropNotAllowed;
22074 this.ghost.update("");
22079 * Updates the contents of the ghost element
22080 * @param {String} html The html that will replace the current innerHTML of the ghost element
22082 update : function(html){
22083 if(typeof html == "string"){
22084 this.ghost.update(html);
22086 this.ghost.update("");
22087 html.style.margin = "0";
22088 this.ghost.dom.appendChild(html);
22090 // ensure float = none set?? cant remember why though.
22091 var el = this.ghost.dom.firstChild;
22093 Roo.fly(el).setStyle('float', 'none');
22098 * Returns the underlying proxy {@link Roo.Layer}
22099 * @return {Roo.Layer} el
22101 getEl : function(){
22106 * Returns the ghost element
22107 * @return {Roo.Element} el
22109 getGhost : function(){
22115 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22117 hide : function(clear){
22125 * Stops the repair animation if it's currently running
22128 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22134 * Displays this proxy
22141 * Force the Layer to sync its shadow and shim positions to the element
22148 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22149 * invalid drop operation by the item being dragged.
22150 * @param {Array} xy The XY position of the element ([x, y])
22151 * @param {Function} callback The function to call after the repair is complete
22152 * @param {Object} scope The scope in which to execute the callback
22154 repair : function(xy, callback, scope){
22155 this.callback = callback;
22156 this.scope = scope;
22157 if(xy && this.animRepair !== false){
22158 this.el.addClass("x-dd-drag-repair");
22159 this.el.hideUnders(true);
22160 this.anim = this.el.shift({
22161 duration: this.repairDuration || .5,
22165 callback: this.afterRepair,
22169 this.afterRepair();
22174 afterRepair : function(){
22176 if(typeof this.callback == "function"){
22177 this.callback.call(this.scope || this);
22179 this.callback = null;
22184 * Ext JS Library 1.1.1
22185 * Copyright(c) 2006-2007, Ext JS, LLC.
22187 * Originally Released Under LGPL - original licence link has changed is not relivant.
22190 * <script type="text/javascript">
22194 * @class Roo.dd.DragSource
22195 * @extends Roo.dd.DDProxy
22196 * A simple class that provides the basic implementation needed to make any element draggable.
22198 * @param {String/HTMLElement/Element} el The container element
22199 * @param {Object} config
22201 Roo.dd.DragSource = function(el, config){
22202 this.el = Roo.get(el);
22203 this.dragData = {};
22205 Roo.apply(this, config);
22208 this.proxy = new Roo.dd.StatusProxy();
22211 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22212 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22214 this.dragging = false;
22217 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22219 * @cfg {String} dropAllowed
22220 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22222 dropAllowed : "x-dd-drop-ok",
22224 * @cfg {String} dropNotAllowed
22225 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22227 dropNotAllowed : "x-dd-drop-nodrop",
22230 * Returns the data object associated with this drag source
22231 * @return {Object} data An object containing arbitrary data
22233 getDragData : function(e){
22234 return this.dragData;
22238 onDragEnter : function(e, id){
22239 var target = Roo.dd.DragDropMgr.getDDById(id);
22240 this.cachedTarget = target;
22241 if(this.beforeDragEnter(target, e, id) !== false){
22242 if(target.isNotifyTarget){
22243 var status = target.notifyEnter(this, e, this.dragData);
22244 this.proxy.setStatus(status);
22246 this.proxy.setStatus(this.dropAllowed);
22249 if(this.afterDragEnter){
22251 * An empty function by default, but provided so that you can perform a custom action
22252 * when the dragged item enters the drop target by providing an implementation.
22253 * @param {Roo.dd.DragDrop} target The drop target
22254 * @param {Event} e The event object
22255 * @param {String} id The id of the dragged element
22256 * @method afterDragEnter
22258 this.afterDragEnter(target, e, id);
22264 * An empty function by default, but provided so that you can perform a custom action
22265 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22266 * @param {Roo.dd.DragDrop} target The drop target
22267 * @param {Event} e The event object
22268 * @param {String} id The id of the dragged element
22269 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22271 beforeDragEnter : function(target, e, id){
22276 alignElWithMouse: function() {
22277 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22282 onDragOver : function(e, id){
22283 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22284 if(this.beforeDragOver(target, e, id) !== false){
22285 if(target.isNotifyTarget){
22286 var status = target.notifyOver(this, e, this.dragData);
22287 this.proxy.setStatus(status);
22290 if(this.afterDragOver){
22292 * An empty function by default, but provided so that you can perform a custom action
22293 * while the dragged item is over the drop target by providing an implementation.
22294 * @param {Roo.dd.DragDrop} target The drop target
22295 * @param {Event} e The event object
22296 * @param {String} id The id of the dragged element
22297 * @method afterDragOver
22299 this.afterDragOver(target, e, id);
22305 * An empty function by default, but provided so that you can perform a custom action
22306 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22307 * @param {Roo.dd.DragDrop} target The drop target
22308 * @param {Event} e The event object
22309 * @param {String} id The id of the dragged element
22310 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22312 beforeDragOver : function(target, e, id){
22317 onDragOut : function(e, id){
22318 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22319 if(this.beforeDragOut(target, e, id) !== false){
22320 if(target.isNotifyTarget){
22321 target.notifyOut(this, e, this.dragData);
22323 this.proxy.reset();
22324 if(this.afterDragOut){
22326 * An empty function by default, but provided so that you can perform a custom action
22327 * after the dragged item is dragged out of the target without dropping.
22328 * @param {Roo.dd.DragDrop} target The drop target
22329 * @param {Event} e The event object
22330 * @param {String} id The id of the dragged element
22331 * @method afterDragOut
22333 this.afterDragOut(target, e, id);
22336 this.cachedTarget = null;
22340 * An empty function by default, but provided so that you can perform a custom action before the dragged
22341 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22342 * @param {Roo.dd.DragDrop} target The drop target
22343 * @param {Event} e The event object
22344 * @param {String} id The id of the dragged element
22345 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22347 beforeDragOut : function(target, e, id){
22352 onDragDrop : function(e, id){
22353 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22354 if(this.beforeDragDrop(target, e, id) !== false){
22355 if(target.isNotifyTarget){
22356 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22357 this.onValidDrop(target, e, id);
22359 this.onInvalidDrop(target, e, id);
22362 this.onValidDrop(target, e, id);
22365 if(this.afterDragDrop){
22367 * An empty function by default, but provided so that you can perform a custom action
22368 * after a valid drag drop has occurred by providing an implementation.
22369 * @param {Roo.dd.DragDrop} target The drop target
22370 * @param {Event} e The event object
22371 * @param {String} id The id of the dropped element
22372 * @method afterDragDrop
22374 this.afterDragDrop(target, e, id);
22377 delete this.cachedTarget;
22381 * An empty function by default, but provided so that you can perform a custom action before the dragged
22382 * item is dropped onto the target and optionally cancel the onDragDrop.
22383 * @param {Roo.dd.DragDrop} target The drop target
22384 * @param {Event} e The event object
22385 * @param {String} id The id of the dragged element
22386 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22388 beforeDragDrop : function(target, e, id){
22393 onValidDrop : function(target, e, id){
22395 if(this.afterValidDrop){
22397 * An empty function by default, but provided so that you can perform a custom action
22398 * after a valid drop has occurred by providing an implementation.
22399 * @param {Object} target The target DD
22400 * @param {Event} e The event object
22401 * @param {String} id The id of the dropped element
22402 * @method afterInvalidDrop
22404 this.afterValidDrop(target, e, id);
22409 getRepairXY : function(e, data){
22410 return this.el.getXY();
22414 onInvalidDrop : function(target, e, id){
22415 this.beforeInvalidDrop(target, e, id);
22416 if(this.cachedTarget){
22417 if(this.cachedTarget.isNotifyTarget){
22418 this.cachedTarget.notifyOut(this, e, this.dragData);
22420 this.cacheTarget = null;
22422 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22424 if(this.afterInvalidDrop){
22426 * An empty function by default, but provided so that you can perform a custom action
22427 * after an invalid drop has occurred by providing an implementation.
22428 * @param {Event} e The event object
22429 * @param {String} id The id of the dropped element
22430 * @method afterInvalidDrop
22432 this.afterInvalidDrop(e, id);
22437 afterRepair : function(){
22439 this.el.highlight(this.hlColor || "c3daf9");
22441 this.dragging = false;
22445 * An empty function by default, but provided so that you can perform a custom action after an invalid
22446 * drop has occurred.
22447 * @param {Roo.dd.DragDrop} target The drop target
22448 * @param {Event} e The event object
22449 * @param {String} id The id of the dragged element
22450 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22452 beforeInvalidDrop : function(target, e, id){
22457 handleMouseDown : function(e){
22458 if(this.dragging) {
22461 var data = this.getDragData(e);
22462 if(data && this.onBeforeDrag(data, e) !== false){
22463 this.dragData = data;
22465 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22470 * An empty function by default, but provided so that you can perform a custom action before the initial
22471 * drag event begins and optionally cancel it.
22472 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22473 * @param {Event} e The event object
22474 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22476 onBeforeDrag : function(data, e){
22481 * An empty function by default, but provided so that you can perform a custom action once the initial
22482 * drag event has begun. The drag cannot be canceled from this function.
22483 * @param {Number} x The x position of the click on the dragged object
22484 * @param {Number} y The y position of the click on the dragged object
22486 onStartDrag : Roo.emptyFn,
22488 // private - YUI override
22489 startDrag : function(x, y){
22490 this.proxy.reset();
22491 this.dragging = true;
22492 this.proxy.update("");
22493 this.onInitDrag(x, y);
22498 onInitDrag : function(x, y){
22499 var clone = this.el.dom.cloneNode(true);
22500 clone.id = Roo.id(); // prevent duplicate ids
22501 this.proxy.update(clone);
22502 this.onStartDrag(x, y);
22507 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22508 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22510 getProxy : function(){
22515 * Hides the drag source's {@link Roo.dd.StatusProxy}
22517 hideProxy : function(){
22519 this.proxy.reset(true);
22520 this.dragging = false;
22524 triggerCacheRefresh : function(){
22525 Roo.dd.DDM.refreshCache(this.groups);
22528 // private - override to prevent hiding
22529 b4EndDrag: function(e) {
22532 // private - override to prevent moving
22533 endDrag : function(e){
22534 this.onEndDrag(this.dragData, e);
22538 onEndDrag : function(data, e){
22541 // private - pin to cursor
22542 autoOffset : function(x, y) {
22543 this.setDelta(-12, -20);
22547 * Ext JS Library 1.1.1
22548 * Copyright(c) 2006-2007, Ext JS, LLC.
22550 * Originally Released Under LGPL - original licence link has changed is not relivant.
22553 * <script type="text/javascript">
22558 * @class Roo.dd.DropTarget
22559 * @extends Roo.dd.DDTarget
22560 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22561 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22563 * @param {String/HTMLElement/Element} el The container element
22564 * @param {Object} config
22566 Roo.dd.DropTarget = function(el, config){
22567 this.el = Roo.get(el);
22569 var listeners = false; ;
22570 if (config && config.listeners) {
22571 listeners= config.listeners;
22572 delete config.listeners;
22574 Roo.apply(this, config);
22576 if(this.containerScroll){
22577 Roo.dd.ScrollManager.register(this.el);
22581 * @scope Roo.dd.DropTarget
22586 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22587 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22588 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22590 * IMPORTANT : it should set this.valid to true|false
22592 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22593 * @param {Event} e The event
22594 * @param {Object} data An object containing arbitrary data supplied by the drag source
22600 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22601 * This method will be called on every mouse movement while the drag source is over the drop target.
22602 * This default implementation simply returns the dropAllowed config value.
22604 * IMPORTANT : it should set this.valid to true|false
22606 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22607 * @param {Event} e The event
22608 * @param {Object} data An object containing arbitrary data supplied by the drag source
22614 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22615 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22616 * overClass (if any) from the drop element.
22619 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22620 * @param {Event} e The event
22621 * @param {Object} data An object containing arbitrary data supplied by the drag source
22627 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22628 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22629 * implementation that does something to process the drop event and returns true so that the drag source's
22630 * repair action does not run.
22632 * IMPORTANT : it should set this.success
22634 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22635 * @param {Event} e The event
22636 * @param {Object} data An object containing arbitrary data supplied by the drag source
22642 Roo.dd.DropTarget.superclass.constructor.call( this,
22644 this.ddGroup || this.group,
22647 listeners : listeners || {}
22655 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22657 * @cfg {String} overClass
22658 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22661 * @cfg {String} ddGroup
22662 * The drag drop group to handle drop events for
22666 * @cfg {String} dropAllowed
22667 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22669 dropAllowed : "x-dd-drop-ok",
22671 * @cfg {String} dropNotAllowed
22672 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22674 dropNotAllowed : "x-dd-drop-nodrop",
22676 * @cfg {boolean} success
22677 * set this after drop listener..
22681 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22682 * if the drop point is valid for over/enter..
22689 isNotifyTarget : true,
22694 notifyEnter : function(dd, e, data)
22697 this.fireEvent('enter', dd, e, data);
22698 if(this.overClass){
22699 this.el.addClass(this.overClass);
22701 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22702 this.valid ? this.dropAllowed : this.dropNotAllowed
22709 notifyOver : function(dd, e, data)
22712 this.fireEvent('over', dd, e, data);
22713 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22714 this.valid ? this.dropAllowed : this.dropNotAllowed
22721 notifyOut : function(dd, e, data)
22723 this.fireEvent('out', dd, e, data);
22724 if(this.overClass){
22725 this.el.removeClass(this.overClass);
22732 notifyDrop : function(dd, e, data)
22734 this.success = false;
22735 this.fireEvent('drop', dd, e, data);
22736 return this.success;
22740 * Ext JS Library 1.1.1
22741 * Copyright(c) 2006-2007, Ext JS, LLC.
22743 * Originally Released Under LGPL - original licence link has changed is not relivant.
22746 * <script type="text/javascript">
22751 * @class Roo.dd.DragZone
22752 * @extends Roo.dd.DragSource
22753 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22754 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22756 * @param {String/HTMLElement/Element} el The container element
22757 * @param {Object} config
22759 Roo.dd.DragZone = function(el, config){
22760 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22761 if(this.containerScroll){
22762 Roo.dd.ScrollManager.register(this.el);
22766 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22768 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22769 * for auto scrolling during drag operations.
22772 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22773 * method after a failed drop (defaults to "c3daf9" - light blue)
22777 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22778 * for a valid target to drag based on the mouse down. Override this method
22779 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22780 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22781 * @param {EventObject} e The mouse down event
22782 * @return {Object} The dragData
22784 getDragData : function(e){
22785 return Roo.dd.Registry.getHandleFromEvent(e);
22789 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22790 * this.dragData.ddel
22791 * @param {Number} x The x position of the click on the dragged object
22792 * @param {Number} y The y position of the click on the dragged object
22793 * @return {Boolean} true to continue the drag, false to cancel
22795 onInitDrag : function(x, y){
22796 this.proxy.update(this.dragData.ddel.cloneNode(true));
22797 this.onStartDrag(x, y);
22802 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22804 afterRepair : function(){
22806 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22808 this.dragging = false;
22812 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22813 * the XY of this.dragData.ddel
22814 * @param {EventObject} e The mouse up event
22815 * @return {Array} The xy location (e.g. [100, 200])
22817 getRepairXY : function(e){
22818 return Roo.Element.fly(this.dragData.ddel).getXY();
22822 * Ext JS Library 1.1.1
22823 * Copyright(c) 2006-2007, Ext JS, LLC.
22825 * Originally Released Under LGPL - original licence link has changed is not relivant.
22828 * <script type="text/javascript">
22831 * @class Roo.dd.DropZone
22832 * @extends Roo.dd.DropTarget
22833 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22834 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22836 * @param {String/HTMLElement/Element} el The container element
22837 * @param {Object} config
22839 Roo.dd.DropZone = function(el, config){
22840 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22843 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22845 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22846 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22847 * provide your own custom lookup.
22848 * @param {Event} e The event
22849 * @return {Object} data The custom data
22851 getTargetFromEvent : function(e){
22852 return Roo.dd.Registry.getTargetFromEvent(e);
22856 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22857 * that it has registered. This method has no default implementation and should be overridden to provide
22858 * node-specific processing if necessary.
22859 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22860 * {@link #getTargetFromEvent} for this node)
22861 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22862 * @param {Event} e The event
22863 * @param {Object} data An object containing arbitrary data supplied by the drag source
22865 onNodeEnter : function(n, dd, e, data){
22870 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22871 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22872 * overridden to provide the proper feedback.
22873 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22874 * {@link #getTargetFromEvent} for this node)
22875 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22876 * @param {Event} e The event
22877 * @param {Object} data An object containing arbitrary data supplied by the drag source
22878 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22879 * underlying {@link Roo.dd.StatusProxy} can be updated
22881 onNodeOver : function(n, dd, e, data){
22882 return this.dropAllowed;
22886 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22887 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22888 * node-specific processing if necessary.
22889 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22890 * {@link #getTargetFromEvent} for this node)
22891 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22892 * @param {Event} e The event
22893 * @param {Object} data An object containing arbitrary data supplied by the drag source
22895 onNodeOut : function(n, dd, e, data){
22900 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22901 * the drop node. The default implementation returns false, so it should be overridden to provide the
22902 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22903 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22904 * {@link #getTargetFromEvent} for this node)
22905 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22906 * @param {Event} e The event
22907 * @param {Object} data An object containing arbitrary data supplied by the drag source
22908 * @return {Boolean} True if the drop was valid, else false
22910 onNodeDrop : function(n, dd, e, data){
22915 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22916 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22917 * it should be overridden to provide the proper feedback if necessary.
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 onContainerOver : function(dd, e, data){
22925 return this.dropNotAllowed;
22929 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22930 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22931 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22932 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22933 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22934 * @param {Event} e The event
22935 * @param {Object} data An object containing arbitrary data supplied by the drag source
22936 * @return {Boolean} True if the drop was valid, else false
22938 onContainerDrop : function(dd, e, data){
22943 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22944 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22945 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22946 * you should override this method and provide a custom implementation.
22947 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22948 * @param {Event} e The event
22949 * @param {Object} data An object containing arbitrary data supplied by the drag source
22950 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22951 * underlying {@link Roo.dd.StatusProxy} can be updated
22953 notifyEnter : function(dd, e, data){
22954 return this.dropNotAllowed;
22958 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22959 * This method will be called on every mouse movement while the drag source is over the drop zone.
22960 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22961 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22962 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22963 * registered node, it will call {@link #onContainerOver}.
22964 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22965 * @param {Event} e The event
22966 * @param {Object} data An object containing arbitrary data supplied by the drag source
22967 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22968 * underlying {@link Roo.dd.StatusProxy} can be updated
22970 notifyOver : function(dd, e, data){
22971 var n = this.getTargetFromEvent(e);
22972 if(!n){ // not over valid drop target
22973 if(this.lastOverNode){
22974 this.onNodeOut(this.lastOverNode, dd, e, data);
22975 this.lastOverNode = null;
22977 return this.onContainerOver(dd, e, data);
22979 if(this.lastOverNode != n){
22980 if(this.lastOverNode){
22981 this.onNodeOut(this.lastOverNode, dd, e, data);
22983 this.onNodeEnter(n, dd, e, data);
22984 this.lastOverNode = n;
22986 return this.onNodeOver(n, dd, e, data);
22990 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22991 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22992 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22993 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22994 * @param {Event} e The event
22995 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22997 notifyOut : function(dd, e, data){
22998 if(this.lastOverNode){
22999 this.onNodeOut(this.lastOverNode, dd, e, data);
23000 this.lastOverNode = null;
23005 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23006 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23007 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23008 * otherwise it will call {@link #onContainerDrop}.
23009 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23010 * @param {Event} e The event
23011 * @param {Object} data An object containing arbitrary data supplied by the drag source
23012 * @return {Boolean} True if the drop was valid, else false
23014 notifyDrop : function(dd, e, data){
23015 if(this.lastOverNode){
23016 this.onNodeOut(this.lastOverNode, dd, e, data);
23017 this.lastOverNode = null;
23019 var n = this.getTargetFromEvent(e);
23021 this.onNodeDrop(n, dd, e, data) :
23022 this.onContainerDrop(dd, e, data);
23026 triggerCacheRefresh : function(){
23027 Roo.dd.DDM.refreshCache(this.groups);
23031 * Ext JS Library 1.1.1
23032 * Copyright(c) 2006-2007, Ext JS, LLC.
23034 * Originally Released Under LGPL - original licence link has changed is not relivant.
23037 * <script type="text/javascript">
23042 * @class Roo.data.SortTypes
23044 * Defines the default sorting (casting?) comparison functions used when sorting data.
23046 Roo.data.SortTypes = {
23048 * Default sort that does nothing
23049 * @param {Mixed} s The value being converted
23050 * @return {Mixed} The comparison value
23052 none : function(s){
23057 * The regular expression used to strip tags
23061 stripTagsRE : /<\/?[^>]+>/gi,
23064 * Strips all HTML tags to sort on text only
23065 * @param {Mixed} s The value being converted
23066 * @return {String} The comparison value
23068 asText : function(s){
23069 return String(s).replace(this.stripTagsRE, "");
23073 * Strips all HTML tags to sort on text only - Case insensitive
23074 * @param {Mixed} s The value being converted
23075 * @return {String} The comparison value
23077 asUCText : function(s){
23078 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23082 * Case insensitive string
23083 * @param {Mixed} s The value being converted
23084 * @return {String} The comparison value
23086 asUCString : function(s) {
23087 return String(s).toUpperCase();
23092 * @param {Mixed} s The value being converted
23093 * @return {Number} The comparison value
23095 asDate : function(s) {
23099 if(s instanceof Date){
23100 return s.getTime();
23102 return Date.parse(String(s));
23107 * @param {Mixed} s The value being converted
23108 * @return {Float} The comparison value
23110 asFloat : function(s) {
23111 var val = parseFloat(String(s).replace(/,/g, ""));
23120 * @param {Mixed} s The value being converted
23121 * @return {Number} The comparison value
23123 asInt : function(s) {
23124 var val = parseInt(String(s).replace(/,/g, ""));
23132 * Ext JS Library 1.1.1
23133 * Copyright(c) 2006-2007, Ext JS, LLC.
23135 * Originally Released Under LGPL - original licence link has changed is not relivant.
23138 * <script type="text/javascript">
23142 * @class Roo.data.Record
23143 * Instances of this class encapsulate both record <em>definition</em> information, and record
23144 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
23145 * to access Records cached in an {@link Roo.data.Store} object.<br>
23147 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
23148 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
23151 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
23153 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
23154 * {@link #create}. The parameters are the same.
23155 * @param {Array} data An associative Array of data values keyed by the field name.
23156 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
23157 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
23158 * not specified an integer id is generated.
23160 Roo.data.Record = function(data, id){
23161 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
23166 * Generate a constructor for a specific record layout.
23167 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
23168 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
23169 * Each field definition object may contain the following properties: <ul>
23170 * <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,
23171 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
23172 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
23173 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
23174 * is being used, then this is a string containing the javascript expression to reference the data relative to
23175 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
23176 * to the data item relative to the record element. If the mapping expression is the same as the field name,
23177 * this may be omitted.</p></li>
23178 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
23179 * <ul><li>auto (Default, implies no conversion)</li>
23184 * <li>date</li></ul></p></li>
23185 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
23186 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
23187 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
23188 * by the Reader into an object that will be stored in the Record. It is passed the
23189 * following parameters:<ul>
23190 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
23192 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
23194 * <br>usage:<br><pre><code>
23195 var TopicRecord = Roo.data.Record.create(
23196 {name: 'title', mapping: 'topic_title'},
23197 {name: 'author', mapping: 'username'},
23198 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
23199 {name: 'lastPost', mapping: 'post_time', type: 'date'},
23200 {name: 'lastPoster', mapping: 'user2'},
23201 {name: 'excerpt', mapping: 'post_text'}
23204 var myNewRecord = new TopicRecord({
23205 title: 'Do my job please',
23208 lastPost: new Date(),
23209 lastPoster: 'Animal',
23210 excerpt: 'No way dude!'
23212 myStore.add(myNewRecord);
23217 Roo.data.Record.create = function(o){
23218 var f = function(){
23219 f.superclass.constructor.apply(this, arguments);
23221 Roo.extend(f, Roo.data.Record);
23222 var p = f.prototype;
23223 p.fields = new Roo.util.MixedCollection(false, function(field){
23226 for(var i = 0, len = o.length; i < len; i++){
23227 p.fields.add(new Roo.data.Field(o[i]));
23229 f.getField = function(name){
23230 return p.fields.get(name);
23235 Roo.data.Record.AUTO_ID = 1000;
23236 Roo.data.Record.EDIT = 'edit';
23237 Roo.data.Record.REJECT = 'reject';
23238 Roo.data.Record.COMMIT = 'commit';
23240 Roo.data.Record.prototype = {
23242 * Readonly flag - true if this record has been modified.
23251 join : function(store){
23252 this.store = store;
23256 * Set the named field to the specified value.
23257 * @param {String} name The name of the field to set.
23258 * @param {Object} value The value to set the field to.
23260 set : function(name, value){
23261 if(this.data[name] == value){
23265 if(!this.modified){
23266 this.modified = {};
23268 if(typeof this.modified[name] == 'undefined'){
23269 this.modified[name] = this.data[name];
23271 this.data[name] = value;
23272 if(!this.editing && this.store){
23273 this.store.afterEdit(this);
23278 * Get the value of the named field.
23279 * @param {String} name The name of the field to get the value of.
23280 * @return {Object} The value of the field.
23282 get : function(name){
23283 return this.data[name];
23287 beginEdit : function(){
23288 this.editing = true;
23289 this.modified = {};
23293 cancelEdit : function(){
23294 this.editing = false;
23295 delete this.modified;
23299 endEdit : function(){
23300 this.editing = false;
23301 if(this.dirty && this.store){
23302 this.store.afterEdit(this);
23307 * Usually called by the {@link Roo.data.Store} which owns the Record.
23308 * Rejects all changes made to the Record since either creation, or the last commit operation.
23309 * Modified fields are reverted to their original values.
23311 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23312 * of reject operations.
23314 reject : function(){
23315 var m = this.modified;
23317 if(typeof m[n] != "function"){
23318 this.data[n] = m[n];
23321 this.dirty = false;
23322 delete this.modified;
23323 this.editing = false;
23325 this.store.afterReject(this);
23330 * Usually called by the {@link Roo.data.Store} which owns the Record.
23331 * Commits all changes made to the Record since either creation, or the last commit operation.
23333 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23334 * of commit operations.
23336 commit : function(){
23337 this.dirty = false;
23338 delete this.modified;
23339 this.editing = false;
23341 this.store.afterCommit(this);
23346 hasError : function(){
23347 return this.error != null;
23351 clearError : function(){
23356 * Creates a copy of this record.
23357 * @param {String} id (optional) A new record id if you don't want to use this record's id
23360 copy : function(newId) {
23361 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
23365 * Ext JS Library 1.1.1
23366 * Copyright(c) 2006-2007, Ext JS, LLC.
23368 * Originally Released Under LGPL - original licence link has changed is not relivant.
23371 * <script type="text/javascript">
23377 * @class Roo.data.Store
23378 * @extends Roo.util.Observable
23379 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
23380 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
23382 * 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
23383 * has no knowledge of the format of the data returned by the Proxy.<br>
23385 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
23386 * instances from the data object. These records are cached and made available through accessor functions.
23388 * Creates a new Store.
23389 * @param {Object} config A config object containing the objects needed for the Store to access data,
23390 * and read the data into Records.
23392 Roo.data.Store = function(config){
23393 this.data = new Roo.util.MixedCollection(false);
23394 this.data.getKey = function(o){
23397 this.baseParams = {};
23399 this.paramNames = {
23404 "multisort" : "_multisort"
23407 if(config && config.data){
23408 this.inlineData = config.data;
23409 delete config.data;
23412 Roo.apply(this, config);
23414 if(this.reader){ // reader passed
23415 this.reader = Roo.factory(this.reader, Roo.data);
23416 this.reader.xmodule = this.xmodule || false;
23417 if(!this.recordType){
23418 this.recordType = this.reader.recordType;
23420 if(this.reader.onMetaChange){
23421 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
23425 if(this.recordType){
23426 this.fields = this.recordType.prototype.fields;
23428 this.modified = [];
23432 * @event datachanged
23433 * Fires when the data cache has changed, and a widget which is using this Store
23434 * as a Record cache should refresh its view.
23435 * @param {Store} this
23437 datachanged : true,
23439 * @event metachange
23440 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
23441 * @param {Store} this
23442 * @param {Object} meta The JSON metadata
23447 * Fires when Records have been added to the Store
23448 * @param {Store} this
23449 * @param {Roo.data.Record[]} records The array of Records added
23450 * @param {Number} index The index at which the record(s) were added
23455 * Fires when a Record has been removed from the Store
23456 * @param {Store} this
23457 * @param {Roo.data.Record} record The Record that was removed
23458 * @param {Number} index The index at which the record was removed
23463 * Fires when a Record has been updated
23464 * @param {Store} this
23465 * @param {Roo.data.Record} record The Record that was updated
23466 * @param {String} operation The update operation being performed. Value may be one of:
23468 Roo.data.Record.EDIT
23469 Roo.data.Record.REJECT
23470 Roo.data.Record.COMMIT
23476 * Fires when the data cache has been cleared.
23477 * @param {Store} this
23481 * @event beforeload
23482 * Fires before a request is made for a new data object. If the beforeload handler returns false
23483 * the load action will be canceled.
23484 * @param {Store} this
23485 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23489 * @event beforeloadadd
23490 * Fires after a new set of Records has been loaded.
23491 * @param {Store} this
23492 * @param {Roo.data.Record[]} records The Records that were loaded
23493 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23495 beforeloadadd : true,
23498 * Fires after a new set of Records has been loaded, before they are added to the store.
23499 * @param {Store} this
23500 * @param {Roo.data.Record[]} records The Records that were loaded
23501 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23502 * @params {Object} return from reader
23506 * @event loadexception
23507 * Fires if an exception occurs in the Proxy during loading.
23508 * Called with the signature of the Proxy's "loadexception" event.
23509 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
23512 * @param {Object} return from JsonData.reader() - success, totalRecords, records
23513 * @param {Object} load options
23514 * @param {Object} jsonData from your request (normally this contains the Exception)
23516 loadexception : true
23520 this.proxy = Roo.factory(this.proxy, Roo.data);
23521 this.proxy.xmodule = this.xmodule || false;
23522 this.relayEvents(this.proxy, ["loadexception"]);
23524 this.sortToggle = {};
23525 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
23527 Roo.data.Store.superclass.constructor.call(this);
23529 if(this.inlineData){
23530 this.loadData(this.inlineData);
23531 delete this.inlineData;
23535 Roo.extend(Roo.data.Store, Roo.util.Observable, {
23537 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
23538 * without a remote query - used by combo/forms at present.
23542 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
23545 * @cfg {Array} data Inline data to be loaded when the store is initialized.
23548 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
23549 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
23552 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
23553 * on any HTTP request
23556 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
23559 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
23563 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
23564 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
23566 remoteSort : false,
23569 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
23570 * loaded or when a record is removed. (defaults to false).
23572 pruneModifiedRecords : false,
23575 lastOptions : null,
23578 * Add Records to the Store and fires the add event.
23579 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23581 add : function(records){
23582 records = [].concat(records);
23583 for(var i = 0, len = records.length; i < len; i++){
23584 records[i].join(this);
23586 var index = this.data.length;
23587 this.data.addAll(records);
23588 this.fireEvent("add", this, records, index);
23592 * Remove a Record from the Store and fires the remove event.
23593 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23595 remove : function(record){
23596 var index = this.data.indexOf(record);
23597 this.data.removeAt(index);
23599 if(this.pruneModifiedRecords){
23600 this.modified.remove(record);
23602 this.fireEvent("remove", this, record, index);
23606 * Remove all Records from the Store and fires the clear event.
23608 removeAll : function(){
23610 if(this.pruneModifiedRecords){
23611 this.modified = [];
23613 this.fireEvent("clear", this);
23617 * Inserts Records to the Store at the given index and fires the add event.
23618 * @param {Number} index The start index at which to insert the passed Records.
23619 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23621 insert : function(index, records){
23622 records = [].concat(records);
23623 for(var i = 0, len = records.length; i < len; i++){
23624 this.data.insert(index, records[i]);
23625 records[i].join(this);
23627 this.fireEvent("add", this, records, index);
23631 * Get the index within the cache of the passed Record.
23632 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23633 * @return {Number} The index of the passed Record. Returns -1 if not found.
23635 indexOf : function(record){
23636 return this.data.indexOf(record);
23640 * Get the index within the cache of the Record with the passed id.
23641 * @param {String} id The id of the Record to find.
23642 * @return {Number} The index of the Record. Returns -1 if not found.
23644 indexOfId : function(id){
23645 return this.data.indexOfKey(id);
23649 * Get the Record with the specified id.
23650 * @param {String} id The id of the Record to find.
23651 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23653 getById : function(id){
23654 return this.data.key(id);
23658 * Get the Record at the specified index.
23659 * @param {Number} index The index of the Record to find.
23660 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23662 getAt : function(index){
23663 return this.data.itemAt(index);
23667 * Returns a range of Records between specified indices.
23668 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23669 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23670 * @return {Roo.data.Record[]} An array of Records
23672 getRange : function(start, end){
23673 return this.data.getRange(start, end);
23677 storeOptions : function(o){
23678 o = Roo.apply({}, o);
23681 this.lastOptions = o;
23685 * Loads the Record cache from the configured Proxy using the configured Reader.
23687 * If using remote paging, then the first load call must specify the <em>start</em>
23688 * and <em>limit</em> properties in the options.params property to establish the initial
23689 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23691 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23692 * and this call will return before the new data has been loaded. Perform any post-processing
23693 * in a callback function, or in a "load" event handler.</strong>
23695 * @param {Object} options An object containing properties which control loading options:<ul>
23696 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23697 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23698 * passed the following arguments:<ul>
23699 * <li>r : Roo.data.Record[]</li>
23700 * <li>options: Options object from the load call</li>
23701 * <li>success: Boolean success indicator</li></ul></li>
23702 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23703 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23706 load : function(options){
23707 options = options || {};
23708 if(this.fireEvent("beforeload", this, options) !== false){
23709 this.storeOptions(options);
23710 var p = Roo.apply(options.params || {}, this.baseParams);
23711 // if meta was not loaded from remote source.. try requesting it.
23712 if (!this.reader.metaFromRemote) {
23713 p._requestMeta = 1;
23715 if(this.sortInfo && this.remoteSort){
23716 var pn = this.paramNames;
23717 p[pn["sort"]] = this.sortInfo.field;
23718 p[pn["dir"]] = this.sortInfo.direction;
23720 if (this.multiSort) {
23721 var pn = this.paramNames;
23722 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23725 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23730 * Reloads the Record cache from the configured Proxy using the configured Reader and
23731 * the options from the last load operation performed.
23732 * @param {Object} options (optional) An object containing properties which may override the options
23733 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23734 * the most recently used options are reused).
23736 reload : function(options){
23737 this.load(Roo.applyIf(options||{}, this.lastOptions));
23741 // Called as a callback by the Reader during a load operation.
23742 loadRecords : function(o, options, success){
23743 if(!o || success === false){
23744 if(success !== false){
23745 this.fireEvent("load", this, [], options, o);
23747 if(options.callback){
23748 options.callback.call(options.scope || this, [], options, false);
23752 // if data returned failure - throw an exception.
23753 if (o.success === false) {
23754 // show a message if no listener is registered.
23755 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23756 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23758 // loadmask wil be hooked into this..
23759 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23762 var r = o.records, t = o.totalRecords || r.length;
23764 this.fireEvent("beforeloadadd", this, r, options, o);
23766 if(!options || options.add !== true){
23767 if(this.pruneModifiedRecords){
23768 this.modified = [];
23770 for(var i = 0, len = r.length; i < len; i++){
23774 this.data = this.snapshot;
23775 delete this.snapshot;
23778 this.data.addAll(r);
23779 this.totalLength = t;
23781 this.fireEvent("datachanged", this);
23783 this.totalLength = Math.max(t, this.data.length+r.length);
23787 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23789 var e = new Roo.data.Record({});
23791 e.set(this.parent.displayField, this.parent.emptyTitle);
23792 e.set(this.parent.valueField, '');
23797 this.fireEvent("load", this, r, options, o);
23798 if(options.callback){
23799 options.callback.call(options.scope || this, r, options, true);
23805 * Loads data from a passed data block. A Reader which understands the format of the data
23806 * must have been configured in the constructor.
23807 * @param {Object} data The data block from which to read the Records. The format of the data expected
23808 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23809 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23811 loadData : function(o, append){
23812 var r = this.reader.readRecords(o);
23813 this.loadRecords(r, {add: append}, true);
23817 * using 'cn' the nested child reader read the child array into it's child stores.
23818 * @param {Object} rec The record with a 'children array
23820 loadDataFromChildren : function(rec)
23822 this.loadData(this.reader.toLoadData(rec));
23827 * Gets the number of cached records.
23829 * <em>If using paging, this may not be the total size of the dataset. If the data object
23830 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23831 * the data set size</em>
23833 getCount : function(){
23834 return this.data.length || 0;
23838 * Gets the total number of records in the dataset as returned by the server.
23840 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23841 * the dataset size</em>
23843 getTotalCount : function(){
23844 return this.totalLength || 0;
23848 * Returns the sort state of the Store as an object with two properties:
23850 field {String} The name of the field by which the Records are sorted
23851 direction {String} The sort order, "ASC" or "DESC"
23854 getSortState : function(){
23855 return this.sortInfo;
23859 applySort : function(){
23860 if(this.sortInfo && !this.remoteSort){
23861 var s = this.sortInfo, f = s.field;
23862 var st = this.fields.get(f).sortType;
23863 var fn = function(r1, r2){
23864 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23865 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23867 this.data.sort(s.direction, fn);
23868 if(this.snapshot && this.snapshot != this.data){
23869 this.snapshot.sort(s.direction, fn);
23875 * Sets the default sort column and order to be used by the next load operation.
23876 * @param {String} fieldName The name of the field to sort by.
23877 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23879 setDefaultSort : function(field, dir){
23880 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23884 * Sort the Records.
23885 * If remote sorting is used, the sort is performed on the server, and the cache is
23886 * reloaded. If local sorting is used, the cache is sorted internally.
23887 * @param {String} fieldName The name of the field to sort by.
23888 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23890 sort : function(fieldName, dir){
23891 var f = this.fields.get(fieldName);
23893 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23895 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23896 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23901 this.sortToggle[f.name] = dir;
23902 this.sortInfo = {field: f.name, direction: dir};
23903 if(!this.remoteSort){
23905 this.fireEvent("datachanged", this);
23907 this.load(this.lastOptions);
23912 * Calls the specified function for each of the Records in the cache.
23913 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23914 * Returning <em>false</em> aborts and exits the iteration.
23915 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23917 each : function(fn, scope){
23918 this.data.each(fn, scope);
23922 * Gets all records modified since the last commit. Modified records are persisted across load operations
23923 * (e.g., during paging).
23924 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23926 getModifiedRecords : function(){
23927 return this.modified;
23931 createFilterFn : function(property, value, anyMatch){
23932 if(!value.exec){ // not a regex
23933 value = String(value);
23934 if(value.length == 0){
23937 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23939 return function(r){
23940 return value.test(r.data[property]);
23945 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23946 * @param {String} property A field on your records
23947 * @param {Number} start The record index to start at (defaults to 0)
23948 * @param {Number} end The last record index to include (defaults to length - 1)
23949 * @return {Number} The sum
23951 sum : function(property, start, end){
23952 var rs = this.data.items, v = 0;
23953 start = start || 0;
23954 end = (end || end === 0) ? end : rs.length-1;
23956 for(var i = start; i <= end; i++){
23957 v += (rs[i].data[property] || 0);
23963 * Filter the records by a specified property.
23964 * @param {String} field A field on your records
23965 * @param {String/RegExp} value Either a string that the field
23966 * should start with or a RegExp to test against the field
23967 * @param {Boolean} anyMatch True to match any part not just the beginning
23969 filter : function(property, value, anyMatch){
23970 var fn = this.createFilterFn(property, value, anyMatch);
23971 return fn ? this.filterBy(fn) : this.clearFilter();
23975 * Filter by a function. The specified function will be called with each
23976 * record in this data source. If the function returns true the record is included,
23977 * otherwise it is filtered.
23978 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23979 * @param {Object} scope (optional) The scope of the function (defaults to this)
23981 filterBy : function(fn, scope){
23982 this.snapshot = this.snapshot || this.data;
23983 this.data = this.queryBy(fn, scope||this);
23984 this.fireEvent("datachanged", this);
23988 * Query the records by a specified property.
23989 * @param {String} field A field on your records
23990 * @param {String/RegExp} value Either a string that the field
23991 * should start with or a RegExp to test against the field
23992 * @param {Boolean} anyMatch True to match any part not just the beginning
23993 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23995 query : function(property, value, anyMatch){
23996 var fn = this.createFilterFn(property, value, anyMatch);
23997 return fn ? this.queryBy(fn) : this.data.clone();
24001 * Query by a function. The specified function will be called with each
24002 * record in this data source. If the function returns true the record is included
24004 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24005 * @param {Object} scope (optional) The scope of the function (defaults to this)
24006 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24008 queryBy : function(fn, scope){
24009 var data = this.snapshot || this.data;
24010 return data.filterBy(fn, scope||this);
24014 * Collects unique values for a particular dataIndex from this store.
24015 * @param {String} dataIndex The property to collect
24016 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24017 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24018 * @return {Array} An array of the unique values
24020 collect : function(dataIndex, allowNull, bypassFilter){
24021 var d = (bypassFilter === true && this.snapshot) ?
24022 this.snapshot.items : this.data.items;
24023 var v, sv, r = [], l = {};
24024 for(var i = 0, len = d.length; i < len; i++){
24025 v = d[i].data[dataIndex];
24027 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24036 * Revert to a view of the Record cache with no filtering applied.
24037 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24039 clearFilter : function(suppressEvent){
24040 if(this.snapshot && this.snapshot != this.data){
24041 this.data = this.snapshot;
24042 delete this.snapshot;
24043 if(suppressEvent !== true){
24044 this.fireEvent("datachanged", this);
24050 afterEdit : function(record){
24051 if(this.modified.indexOf(record) == -1){
24052 this.modified.push(record);
24054 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24058 afterReject : function(record){
24059 this.modified.remove(record);
24060 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24064 afterCommit : function(record){
24065 this.modified.remove(record);
24066 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24070 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24071 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24073 commitChanges : function(){
24074 var m = this.modified.slice(0);
24075 this.modified = [];
24076 for(var i = 0, len = m.length; i < len; i++){
24082 * Cancel outstanding changes on all changed records.
24084 rejectChanges : function(){
24085 var m = this.modified.slice(0);
24086 this.modified = [];
24087 for(var i = 0, len = m.length; i < len; i++){
24092 onMetaChange : function(meta, rtype, o){
24093 this.recordType = rtype;
24094 this.fields = rtype.prototype.fields;
24095 delete this.snapshot;
24096 this.sortInfo = meta.sortInfo || this.sortInfo;
24097 this.modified = [];
24098 this.fireEvent('metachange', this, this.reader.meta);
24101 moveIndex : function(data, type)
24103 var index = this.indexOf(data);
24105 var newIndex = index + type;
24109 this.insert(newIndex, data);
24114 * Ext JS Library 1.1.1
24115 * Copyright(c) 2006-2007, Ext JS, LLC.
24117 * Originally Released Under LGPL - original licence link has changed is not relivant.
24120 * <script type="text/javascript">
24124 * @class Roo.data.SimpleStore
24125 * @extends Roo.data.Store
24126 * Small helper class to make creating Stores from Array data easier.
24127 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24128 * @cfg {Array} fields An array of field definition objects, or field name strings.
24129 * @cfg {Object} an existing reader (eg. copied from another store)
24130 * @cfg {Array} data The multi-dimensional array of data
24132 * @param {Object} config
24134 Roo.data.SimpleStore = function(config)
24136 Roo.data.SimpleStore.superclass.constructor.call(this, {
24138 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24141 Roo.data.Record.create(config.fields)
24143 proxy : new Roo.data.MemoryProxy(config.data)
24147 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24149 * Ext JS Library 1.1.1
24150 * Copyright(c) 2006-2007, Ext JS, LLC.
24152 * Originally Released Under LGPL - original licence link has changed is not relivant.
24155 * <script type="text/javascript">
24160 * @extends Roo.data.Store
24161 * @class Roo.data.JsonStore
24162 * Small helper class to make creating Stores for JSON data easier. <br/>
24164 var store = new Roo.data.JsonStore({
24165 url: 'get-images.php',
24167 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24170 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24171 * JsonReader and HttpProxy (unless inline data is provided).</b>
24172 * @cfg {Array} fields An array of field definition objects, or field name strings.
24174 * @param {Object} config
24176 Roo.data.JsonStore = function(c){
24177 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24178 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24179 reader: new Roo.data.JsonReader(c, c.fields)
24182 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
24184 * Ext JS Library 1.1.1
24185 * Copyright(c) 2006-2007, Ext JS, LLC.
24187 * Originally Released Under LGPL - original licence link has changed is not relivant.
24190 * <script type="text/javascript">
24194 Roo.data.Field = function(config){
24195 if(typeof config == "string"){
24196 config = {name: config};
24198 Roo.apply(this, config);
24201 this.type = "auto";
24204 var st = Roo.data.SortTypes;
24205 // named sortTypes are supported, here we look them up
24206 if(typeof this.sortType == "string"){
24207 this.sortType = st[this.sortType];
24210 // set default sortType for strings and dates
24211 if(!this.sortType){
24214 this.sortType = st.asUCString;
24217 this.sortType = st.asDate;
24220 this.sortType = st.none;
24225 var stripRe = /[\$,%]/g;
24227 // prebuilt conversion function for this field, instead of
24228 // switching every time we're reading a value
24230 var cv, dateFormat = this.dateFormat;
24235 cv = function(v){ return v; };
24238 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24242 return v !== undefined && v !== null && v !== '' ?
24243 parseInt(String(v).replace(stripRe, ""), 10) : '';
24248 return v !== undefined && v !== null && v !== '' ?
24249 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24254 cv = function(v){ return v === true || v === "true" || v == 1; };
24261 if(v instanceof Date){
24265 if(dateFormat == "timestamp"){
24266 return new Date(v*1000);
24268 return Date.parseDate(v, dateFormat);
24270 var parsed = Date.parse(v);
24271 return parsed ? new Date(parsed) : null;
24280 Roo.data.Field.prototype = {
24288 * Ext JS Library 1.1.1
24289 * Copyright(c) 2006-2007, Ext JS, LLC.
24291 * Originally Released Under LGPL - original licence link has changed is not relivant.
24294 * <script type="text/javascript">
24297 // Base class for reading structured data from a data source. This class is intended to be
24298 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24301 * @class Roo.data.DataReader
24302 * Base class for reading structured data from a data source. This class is intended to be
24303 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24306 Roo.data.DataReader = function(meta, recordType){
24310 this.recordType = recordType instanceof Array ?
24311 Roo.data.Record.create(recordType) : recordType;
24314 Roo.data.DataReader.prototype = {
24317 readerType : 'Data',
24319 * Create an empty record
24320 * @param {Object} data (optional) - overlay some values
24321 * @return {Roo.data.Record} record created.
24323 newRow : function(d) {
24325 this.recordType.prototype.fields.each(function(c) {
24327 case 'int' : da[c.name] = 0; break;
24328 case 'date' : da[c.name] = new Date(); break;
24329 case 'float' : da[c.name] = 0.0; break;
24330 case 'boolean' : da[c.name] = false; break;
24331 default : da[c.name] = ""; break;
24335 return new this.recordType(Roo.apply(da, d));
24341 * Ext JS Library 1.1.1
24342 * Copyright(c) 2006-2007, Ext JS, LLC.
24344 * Originally Released Under LGPL - original licence link has changed is not relivant.
24347 * <script type="text/javascript">
24351 * @class Roo.data.DataProxy
24352 * @extends Roo.data.Observable
24353 * This class is an abstract base class for implementations which provide retrieval of
24354 * unformatted data objects.<br>
24356 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24357 * (of the appropriate type which knows how to parse the data object) to provide a block of
24358 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24360 * Custom implementations must implement the load method as described in
24361 * {@link Roo.data.HttpProxy#load}.
24363 Roo.data.DataProxy = function(){
24366 * @event beforeload
24367 * Fires before a network request is made to retrieve a data object.
24368 * @param {Object} This DataProxy object.
24369 * @param {Object} params The params parameter to the load function.
24374 * Fires before the load method's callback is called.
24375 * @param {Object} This DataProxy object.
24376 * @param {Object} o The data object.
24377 * @param {Object} arg The callback argument object passed to the load function.
24381 * @event loadexception
24382 * Fires if an Exception occurs during data retrieval.
24383 * @param {Object} This DataProxy object.
24384 * @param {Object} o The data object.
24385 * @param {Object} arg The callback argument object passed to the load function.
24386 * @param {Object} e The Exception.
24388 loadexception : true
24390 Roo.data.DataProxy.superclass.constructor.call(this);
24393 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24396 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24400 * Ext JS Library 1.1.1
24401 * Copyright(c) 2006-2007, Ext JS, LLC.
24403 * Originally Released Under LGPL - original licence link has changed is not relivant.
24406 * <script type="text/javascript">
24409 * @class Roo.data.MemoryProxy
24410 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24411 * to the Reader when its load method is called.
24413 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24415 Roo.data.MemoryProxy = function(data){
24419 Roo.data.MemoryProxy.superclass.constructor.call(this);
24423 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24426 * Load data from the requested source (in this case an in-memory
24427 * data object passed to the constructor), read the data object into
24428 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24429 * process that block using the passed callback.
24430 * @param {Object} params This parameter is not used by the MemoryProxy class.
24431 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24432 * object into a block of Roo.data.Records.
24433 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24434 * The function must be passed <ul>
24435 * <li>The Record block object</li>
24436 * <li>The "arg" argument from the load function</li>
24437 * <li>A boolean success indicator</li>
24439 * @param {Object} scope The scope in which to call the callback
24440 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24442 load : function(params, reader, callback, scope, arg){
24443 params = params || {};
24446 result = reader.readRecords(params.data ? params.data :this.data);
24448 this.fireEvent("loadexception", this, arg, null, e);
24449 callback.call(scope, null, arg, false);
24452 callback.call(scope, result, arg, true);
24456 update : function(params, records){
24461 * Ext JS Library 1.1.1
24462 * Copyright(c) 2006-2007, Ext JS, LLC.
24464 * Originally Released Under LGPL - original licence link has changed is not relivant.
24467 * <script type="text/javascript">
24470 * @class Roo.data.HttpProxy
24471 * @extends Roo.data.DataProxy
24472 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24473 * configured to reference a certain URL.<br><br>
24475 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24476 * from which the running page was served.<br><br>
24478 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24480 * Be aware that to enable the browser to parse an XML document, the server must set
24481 * the Content-Type header in the HTTP response to "text/xml".
24483 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24484 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24485 * will be used to make the request.
24487 Roo.data.HttpProxy = function(conn){
24488 Roo.data.HttpProxy.superclass.constructor.call(this);
24489 // is conn a conn config or a real conn?
24491 this.useAjax = !conn || !conn.events;
24495 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24496 // thse are take from connection...
24499 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24502 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24503 * extra parameters to each request made by this object. (defaults to undefined)
24506 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24507 * to each request made by this object. (defaults to undefined)
24510 * @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)
24513 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24516 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24522 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24526 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24527 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24528 * a finer-grained basis than the DataProxy events.
24530 getConnection : function(){
24531 return this.useAjax ? Roo.Ajax : this.conn;
24535 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24536 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24537 * process that block using the passed callback.
24538 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24539 * for the request to the remote server.
24540 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24541 * object into a block of Roo.data.Records.
24542 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24543 * The function must be passed <ul>
24544 * <li>The Record block object</li>
24545 * <li>The "arg" argument from the load function</li>
24546 * <li>A boolean success indicator</li>
24548 * @param {Object} scope The scope in which to call the callback
24549 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24551 load : function(params, reader, callback, scope, arg){
24552 if(this.fireEvent("beforeload", this, params) !== false){
24554 params : params || {},
24556 callback : callback,
24561 callback : this.loadResponse,
24565 Roo.applyIf(o, this.conn);
24566 if(this.activeRequest){
24567 Roo.Ajax.abort(this.activeRequest);
24569 this.activeRequest = Roo.Ajax.request(o);
24571 this.conn.request(o);
24574 callback.call(scope||this, null, arg, false);
24579 loadResponse : function(o, success, response){
24580 delete this.activeRequest;
24582 this.fireEvent("loadexception", this, o, response);
24583 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24588 result = o.reader.read(response);
24590 this.fireEvent("loadexception", this, o, response, e);
24591 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24595 this.fireEvent("load", this, o, o.request.arg);
24596 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24600 update : function(dataSet){
24605 updateResponse : function(dataSet){
24610 * Ext JS Library 1.1.1
24611 * Copyright(c) 2006-2007, Ext JS, LLC.
24613 * Originally Released Under LGPL - original licence link has changed is not relivant.
24616 * <script type="text/javascript">
24620 * @class Roo.data.ScriptTagProxy
24621 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24622 * other than the originating domain of the running page.<br><br>
24624 * <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
24625 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24627 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24628 * source code that is used as the source inside a <script> tag.<br><br>
24630 * In order for the browser to process the returned data, the server must wrap the data object
24631 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24632 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24633 * depending on whether the callback name was passed:
24636 boolean scriptTag = false;
24637 String cb = request.getParameter("callback");
24640 response.setContentType("text/javascript");
24642 response.setContentType("application/x-json");
24644 Writer out = response.getWriter();
24646 out.write(cb + "(");
24648 out.print(dataBlock.toJsonString());
24655 * @param {Object} config A configuration object.
24657 Roo.data.ScriptTagProxy = function(config){
24658 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24659 Roo.apply(this, config);
24660 this.head = document.getElementsByTagName("head")[0];
24663 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24665 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24667 * @cfg {String} url The URL from which to request the data object.
24670 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24674 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24675 * the server the name of the callback function set up by the load call to process the returned data object.
24676 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24677 * javascript output which calls this named function passing the data object as its only parameter.
24679 callbackParam : "callback",
24681 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24682 * name to the request.
24687 * Load data from the configured URL, read the data object into
24688 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24689 * process that block using the passed callback.
24690 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24691 * for the request to the remote server.
24692 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24693 * object into a block of Roo.data.Records.
24694 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24695 * The function must be passed <ul>
24696 * <li>The Record block object</li>
24697 * <li>The "arg" argument from the load function</li>
24698 * <li>A boolean success indicator</li>
24700 * @param {Object} scope The scope in which to call the callback
24701 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24703 load : function(params, reader, callback, scope, arg){
24704 if(this.fireEvent("beforeload", this, params) !== false){
24706 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24708 var url = this.url;
24709 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24711 url += "&_dc=" + (new Date().getTime());
24713 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24716 cb : "stcCallback"+transId,
24717 scriptId : "stcScript"+transId,
24721 callback : callback,
24727 window[trans.cb] = function(o){
24728 conn.handleResponse(o, trans);
24731 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24733 if(this.autoAbort !== false){
24737 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24739 var script = document.createElement("script");
24740 script.setAttribute("src", url);
24741 script.setAttribute("type", "text/javascript");
24742 script.setAttribute("id", trans.scriptId);
24743 this.head.appendChild(script);
24745 this.trans = trans;
24747 callback.call(scope||this, null, arg, false);
24752 isLoading : function(){
24753 return this.trans ? true : false;
24757 * Abort the current server request.
24759 abort : function(){
24760 if(this.isLoading()){
24761 this.destroyTrans(this.trans);
24766 destroyTrans : function(trans, isLoaded){
24767 this.head.removeChild(document.getElementById(trans.scriptId));
24768 clearTimeout(trans.timeoutId);
24770 window[trans.cb] = undefined;
24772 delete window[trans.cb];
24775 // if hasn't been loaded, wait for load to remove it to prevent script error
24776 window[trans.cb] = function(){
24777 window[trans.cb] = undefined;
24779 delete window[trans.cb];
24786 handleResponse : function(o, trans){
24787 this.trans = false;
24788 this.destroyTrans(trans, true);
24791 result = trans.reader.readRecords(o);
24793 this.fireEvent("loadexception", this, o, trans.arg, e);
24794 trans.callback.call(trans.scope||window, null, trans.arg, false);
24797 this.fireEvent("load", this, o, trans.arg);
24798 trans.callback.call(trans.scope||window, result, trans.arg, true);
24802 handleFailure : function(trans){
24803 this.trans = false;
24804 this.destroyTrans(trans, false);
24805 this.fireEvent("loadexception", this, null, trans.arg);
24806 trans.callback.call(trans.scope||window, null, trans.arg, false);
24810 * Ext JS Library 1.1.1
24811 * Copyright(c) 2006-2007, Ext JS, LLC.
24813 * Originally Released Under LGPL - original licence link has changed is not relivant.
24816 * <script type="text/javascript">
24820 * @class Roo.data.JsonReader
24821 * @extends Roo.data.DataReader
24822 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24823 * based on mappings in a provided Roo.data.Record constructor.
24825 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24826 * in the reply previously.
24831 var RecordDef = Roo.data.Record.create([
24832 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24833 {name: 'occupation'} // This field will use "occupation" as the mapping.
24835 var myReader = new Roo.data.JsonReader({
24836 totalProperty: "results", // The property which contains the total dataset size (optional)
24837 root: "rows", // The property which contains an Array of row objects
24838 id: "id" // The property within each row object that provides an ID for the record (optional)
24842 * This would consume a JSON file like this:
24844 { 'results': 2, 'rows': [
24845 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24846 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24849 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24850 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24851 * paged from the remote server.
24852 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24853 * @cfg {String} root name of the property which contains the Array of row objects.
24854 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24855 * @cfg {Array} fields Array of field definition objects
24857 * Create a new JsonReader
24858 * @param {Object} meta Metadata configuration options
24859 * @param {Object} recordType Either an Array of field definition objects,
24860 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24862 Roo.data.JsonReader = function(meta, recordType){
24865 // set some defaults:
24866 Roo.applyIf(meta, {
24867 totalProperty: 'total',
24868 successProperty : 'success',
24873 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24875 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24877 readerType : 'Json',
24880 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24881 * Used by Store query builder to append _requestMeta to params.
24884 metaFromRemote : false,
24886 * This method is only used by a DataProxy which has retrieved data from a remote server.
24887 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24888 * @return {Object} data A data block which is used by an Roo.data.Store object as
24889 * a cache of Roo.data.Records.
24891 read : function(response){
24892 var json = response.responseText;
24894 var o = /* eval:var:o */ eval("("+json+")");
24896 throw {message: "JsonReader.read: Json object not found"};
24902 this.metaFromRemote = true;
24903 this.meta = o.metaData;
24904 this.recordType = Roo.data.Record.create(o.metaData.fields);
24905 this.onMetaChange(this.meta, this.recordType, o);
24907 return this.readRecords(o);
24910 // private function a store will implement
24911 onMetaChange : function(meta, recordType, o){
24918 simpleAccess: function(obj, subsc) {
24925 getJsonAccessor: function(){
24927 return function(expr) {
24929 return(re.test(expr))
24930 ? new Function("obj", "return obj." + expr)
24935 return Roo.emptyFn;
24940 * Create a data block containing Roo.data.Records from an XML document.
24941 * @param {Object} o An object which contains an Array of row objects in the property specified
24942 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24943 * which contains the total size of the dataset.
24944 * @return {Object} data A data block which is used by an Roo.data.Store object as
24945 * a cache of Roo.data.Records.
24947 readRecords : function(o){
24949 * After any data loads, the raw JSON data is available for further custom processing.
24953 var s = this.meta, Record = this.recordType,
24954 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24956 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24958 if(s.totalProperty) {
24959 this.getTotal = this.getJsonAccessor(s.totalProperty);
24961 if(s.successProperty) {
24962 this.getSuccess = this.getJsonAccessor(s.successProperty);
24964 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24966 var g = this.getJsonAccessor(s.id);
24967 this.getId = function(rec) {
24969 return (r === undefined || r === "") ? null : r;
24972 this.getId = function(){return null;};
24975 for(var jj = 0; jj < fl; jj++){
24977 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24978 this.ef[jj] = this.getJsonAccessor(map);
24982 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24983 if(s.totalProperty){
24984 var vt = parseInt(this.getTotal(o), 10);
24989 if(s.successProperty){
24990 var vs = this.getSuccess(o);
24991 if(vs === false || vs === 'false'){
24996 for(var i = 0; i < c; i++){
24999 var id = this.getId(n);
25000 for(var j = 0; j < fl; j++){
25002 var v = this.ef[j](n);
25004 Roo.log('missing convert for ' + f.name);
25008 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25010 var record = new Record(values, id);
25012 records[i] = record;
25018 totalRecords : totalRecords
25021 // used when loading children.. @see loadDataFromChildren
25022 toLoadData: function(rec)
25024 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25025 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25026 return { data : data, total : data.length };
25031 * Ext JS Library 1.1.1
25032 * Copyright(c) 2006-2007, Ext JS, LLC.
25034 * Originally Released Under LGPL - original licence link has changed is not relivant.
25037 * <script type="text/javascript">
25041 * @class Roo.data.XmlReader
25042 * @extends Roo.data.DataReader
25043 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25044 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25046 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25047 * header in the HTTP response must be set to "text/xml".</em>
25051 var RecordDef = Roo.data.Record.create([
25052 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25053 {name: 'occupation'} // This field will use "occupation" as the mapping.
25055 var myReader = new Roo.data.XmlReader({
25056 totalRecords: "results", // The element which contains the total dataset size (optional)
25057 record: "row", // The repeated element which contains row information
25058 id: "id" // The element within the row that provides an ID for the record (optional)
25062 * This would consume an XML file like this:
25066 <results>2</results>
25069 <name>Bill</name>
25070 <occupation>Gardener</occupation>
25074 <name>Ben</name>
25075 <occupation>Horticulturalist</occupation>
25079 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25080 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25081 * paged from the remote server.
25082 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25083 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25084 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25085 * a record identifier value.
25087 * Create a new XmlReader
25088 * @param {Object} meta Metadata configuration options
25089 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25090 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25091 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25093 Roo.data.XmlReader = function(meta, recordType){
25095 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25097 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25099 readerType : 'Xml',
25102 * This method is only used by a DataProxy which has retrieved data from a remote server.
25103 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25104 * to contain a method called 'responseXML' that returns an XML document object.
25105 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25106 * a cache of Roo.data.Records.
25108 read : function(response){
25109 var doc = response.responseXML;
25111 throw {message: "XmlReader.read: XML Document not available"};
25113 return this.readRecords(doc);
25117 * Create a data block containing Roo.data.Records from an XML document.
25118 * @param {Object} doc A parsed XML document.
25119 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25120 * a cache of Roo.data.Records.
25122 readRecords : function(doc){
25124 * After any data loads/reads, the raw XML Document is available for further custom processing.
25125 * @type XMLDocument
25127 this.xmlData = doc;
25128 var root = doc.documentElement || doc;
25129 var q = Roo.DomQuery;
25130 var recordType = this.recordType, fields = recordType.prototype.fields;
25131 var sid = this.meta.id;
25132 var totalRecords = 0, success = true;
25133 if(this.meta.totalRecords){
25134 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25137 if(this.meta.success){
25138 var sv = q.selectValue(this.meta.success, root, true);
25139 success = sv !== false && sv !== 'false';
25142 var ns = q.select(this.meta.record, root);
25143 for(var i = 0, len = ns.length; i < len; i++) {
25146 var id = sid ? q.selectValue(sid, n) : undefined;
25147 for(var j = 0, jlen = fields.length; j < jlen; j++){
25148 var f = fields.items[j];
25149 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25151 values[f.name] = v;
25153 var record = new recordType(values, id);
25155 records[records.length] = record;
25161 totalRecords : totalRecords || records.length
25166 * Ext JS Library 1.1.1
25167 * Copyright(c) 2006-2007, Ext JS, LLC.
25169 * Originally Released Under LGPL - original licence link has changed is not relivant.
25172 * <script type="text/javascript">
25176 * @class Roo.data.ArrayReader
25177 * @extends Roo.data.DataReader
25178 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25179 * Each element of that Array represents a row of data fields. The
25180 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25181 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25185 var RecordDef = Roo.data.Record.create([
25186 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25187 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25189 var myReader = new Roo.data.ArrayReader({
25190 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25194 * This would consume an Array like this:
25196 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25200 * Create a new JsonReader
25201 * @param {Object} meta Metadata configuration options.
25202 * @param {Object|Array} recordType Either an Array of field definition objects
25204 * @cfg {Array} fields Array of field definition objects
25205 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25206 * as specified to {@link Roo.data.Record#create},
25207 * or an {@link Roo.data.Record} object
25210 * created using {@link Roo.data.Record#create}.
25212 Roo.data.ArrayReader = function(meta, recordType)
25214 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25217 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25220 * Create a data block containing Roo.data.Records from an XML document.
25221 * @param {Object} o An Array of row objects which represents the dataset.
25222 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25223 * a cache of Roo.data.Records.
25225 readRecords : function(o)
25227 var sid = this.meta ? this.meta.id : null;
25228 var recordType = this.recordType, fields = recordType.prototype.fields;
25231 for(var i = 0; i < root.length; i++){
25234 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25235 for(var j = 0, jlen = fields.length; j < jlen; j++){
25236 var f = fields.items[j];
25237 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25238 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25240 values[f.name] = v;
25242 var record = new recordType(values, id);
25244 records[records.length] = record;
25248 totalRecords : records.length
25251 // used when loading children.. @see loadDataFromChildren
25252 toLoadData: function(rec)
25254 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25255 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25262 * Ext JS Library 1.1.1
25263 * Copyright(c) 2006-2007, Ext JS, LLC.
25265 * Originally Released Under LGPL - original licence link has changed is not relivant.
25268 * <script type="text/javascript">
25273 * @class Roo.data.Tree
25274 * @extends Roo.util.Observable
25275 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25276 * in the tree have most standard DOM functionality.
25278 * @param {Node} root (optional) The root node
25280 Roo.data.Tree = function(root){
25281 this.nodeHash = {};
25283 * The root node for this tree
25288 this.setRootNode(root);
25293 * Fires when a new child node is appended to a node in this tree.
25294 * @param {Tree} tree The owner tree
25295 * @param {Node} parent The parent node
25296 * @param {Node} node The newly appended node
25297 * @param {Number} index The index of the newly appended node
25302 * Fires when a child node is removed from a node in this tree.
25303 * @param {Tree} tree The owner tree
25304 * @param {Node} parent The parent node
25305 * @param {Node} node The child node removed
25310 * Fires when a node is moved to a new location in the tree
25311 * @param {Tree} tree The owner tree
25312 * @param {Node} node The node moved
25313 * @param {Node} oldParent The old parent of this node
25314 * @param {Node} newParent The new parent of this node
25315 * @param {Number} index The index it was moved to
25320 * Fires when a new child node is inserted in a node in this tree.
25321 * @param {Tree} tree The owner tree
25322 * @param {Node} parent The parent node
25323 * @param {Node} node The child node inserted
25324 * @param {Node} refNode The child node the node was inserted before
25328 * @event beforeappend
25329 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25330 * @param {Tree} tree The owner tree
25331 * @param {Node} parent The parent node
25332 * @param {Node} node The child node to be appended
25334 "beforeappend" : true,
25336 * @event beforeremove
25337 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25338 * @param {Tree} tree The owner tree
25339 * @param {Node} parent The parent node
25340 * @param {Node} node The child node to be removed
25342 "beforeremove" : true,
25344 * @event beforemove
25345 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25346 * @param {Tree} tree The owner tree
25347 * @param {Node} node The node being moved
25348 * @param {Node} oldParent The parent of the node
25349 * @param {Node} newParent The new parent the node is moving to
25350 * @param {Number} index The index it is being moved to
25352 "beforemove" : true,
25354 * @event beforeinsert
25355 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25356 * @param {Tree} tree The owner tree
25357 * @param {Node} parent The parent node
25358 * @param {Node} node The child node to be inserted
25359 * @param {Node} refNode The child node the node is being inserted before
25361 "beforeinsert" : true
25364 Roo.data.Tree.superclass.constructor.call(this);
25367 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25368 pathSeparator: "/",
25370 proxyNodeEvent : function(){
25371 return this.fireEvent.apply(this, arguments);
25375 * Returns the root node for this tree.
25378 getRootNode : function(){
25383 * Sets the root node for this tree.
25384 * @param {Node} node
25387 setRootNode : function(node){
25389 node.ownerTree = this;
25390 node.isRoot = true;
25391 this.registerNode(node);
25396 * Gets a node in this tree by its id.
25397 * @param {String} id
25400 getNodeById : function(id){
25401 return this.nodeHash[id];
25404 registerNode : function(node){
25405 this.nodeHash[node.id] = node;
25408 unregisterNode : function(node){
25409 delete this.nodeHash[node.id];
25412 toString : function(){
25413 return "[Tree"+(this.id?" "+this.id:"")+"]";
25418 * @class Roo.data.Node
25419 * @extends Roo.util.Observable
25420 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25421 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25423 * @param {Object} attributes The attributes/config for the node
25425 Roo.data.Node = function(attributes){
25427 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25430 this.attributes = attributes || {};
25431 this.leaf = this.attributes.leaf;
25433 * The node id. @type String
25435 this.id = this.attributes.id;
25437 this.id = Roo.id(null, "ynode-");
25438 this.attributes.id = this.id;
25443 * All child nodes of this node. @type Array
25445 this.childNodes = [];
25446 if(!this.childNodes.indexOf){ // indexOf is a must
25447 this.childNodes.indexOf = function(o){
25448 for(var i = 0, len = this.length; i < len; i++){
25457 * The parent node for this node. @type Node
25459 this.parentNode = null;
25461 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25463 this.firstChild = null;
25465 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25467 this.lastChild = null;
25469 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25471 this.previousSibling = null;
25473 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25475 this.nextSibling = null;
25480 * Fires when a new child node is appended
25481 * @param {Tree} tree The owner tree
25482 * @param {Node} this This node
25483 * @param {Node} node The newly appended node
25484 * @param {Number} index The index of the newly appended node
25489 * Fires when a child node is removed
25490 * @param {Tree} tree The owner tree
25491 * @param {Node} this This node
25492 * @param {Node} node The removed node
25497 * Fires when this node is moved to a new location in the tree
25498 * @param {Tree} tree The owner tree
25499 * @param {Node} this This node
25500 * @param {Node} oldParent The old parent of this node
25501 * @param {Node} newParent The new parent of this node
25502 * @param {Number} index The index it was moved to
25507 * Fires when a new child node is inserted.
25508 * @param {Tree} tree The owner tree
25509 * @param {Node} this This node
25510 * @param {Node} node The child node inserted
25511 * @param {Node} refNode The child node the node was inserted before
25515 * @event beforeappend
25516 * Fires before a new child is appended, return false to cancel the append.
25517 * @param {Tree} tree The owner tree
25518 * @param {Node} this This node
25519 * @param {Node} node The child node to be appended
25521 "beforeappend" : true,
25523 * @event beforeremove
25524 * Fires before a child is removed, return false to cancel the remove.
25525 * @param {Tree} tree The owner tree
25526 * @param {Node} this This node
25527 * @param {Node} node The child node to be removed
25529 "beforeremove" : true,
25531 * @event beforemove
25532 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25533 * @param {Tree} tree The owner tree
25534 * @param {Node} this This node
25535 * @param {Node} oldParent The parent of this node
25536 * @param {Node} newParent The new parent this node is moving to
25537 * @param {Number} index The index it is being moved to
25539 "beforemove" : true,
25541 * @event beforeinsert
25542 * Fires before a new child is inserted, return false to cancel the insert.
25543 * @param {Tree} tree The owner tree
25544 * @param {Node} this This node
25545 * @param {Node} node The child node to be inserted
25546 * @param {Node} refNode The child node the node is being inserted before
25548 "beforeinsert" : true
25550 this.listeners = this.attributes.listeners;
25551 Roo.data.Node.superclass.constructor.call(this);
25554 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25555 fireEvent : function(evtName){
25556 // first do standard event for this node
25557 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25560 // then bubble it up to the tree if the event wasn't cancelled
25561 var ot = this.getOwnerTree();
25563 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25571 * Returns true if this node is a leaf
25572 * @return {Boolean}
25574 isLeaf : function(){
25575 return this.leaf === true;
25579 setFirstChild : function(node){
25580 this.firstChild = node;
25584 setLastChild : function(node){
25585 this.lastChild = node;
25590 * Returns true if this node is the last child of its parent
25591 * @return {Boolean}
25593 isLast : function(){
25594 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25598 * Returns true if this node is the first child of its parent
25599 * @return {Boolean}
25601 isFirst : function(){
25602 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25605 hasChildNodes : function(){
25606 return !this.isLeaf() && this.childNodes.length > 0;
25610 * Insert node(s) as the last child node of this node.
25611 * @param {Node/Array} node The node or Array of nodes to append
25612 * @return {Node} The appended node if single append, or null if an array was passed
25614 appendChild : function(node){
25616 if(node instanceof Array){
25618 }else if(arguments.length > 1){
25622 // if passed an array or multiple args do them one by one
25624 for(var i = 0, len = multi.length; i < len; i++) {
25625 this.appendChild(multi[i]);
25628 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25631 var index = this.childNodes.length;
25632 var oldParent = node.parentNode;
25633 // it's a move, make sure we move it cleanly
25635 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25638 oldParent.removeChild(node);
25641 index = this.childNodes.length;
25643 this.setFirstChild(node);
25645 this.childNodes.push(node);
25646 node.parentNode = this;
25647 var ps = this.childNodes[index-1];
25649 node.previousSibling = ps;
25650 ps.nextSibling = node;
25652 node.previousSibling = null;
25654 node.nextSibling = null;
25655 this.setLastChild(node);
25656 node.setOwnerTree(this.getOwnerTree());
25657 this.fireEvent("append", this.ownerTree, this, node, index);
25658 if(this.ownerTree) {
25659 this.ownerTree.fireEvent("appendnode", this, node, index);
25662 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25669 * Removes a child node from this node.
25670 * @param {Node} node The node to remove
25671 * @return {Node} The removed node
25673 removeChild : function(node){
25674 var index = this.childNodes.indexOf(node);
25678 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25682 // remove it from childNodes collection
25683 this.childNodes.splice(index, 1);
25686 if(node.previousSibling){
25687 node.previousSibling.nextSibling = node.nextSibling;
25689 if(node.nextSibling){
25690 node.nextSibling.previousSibling = node.previousSibling;
25693 // update child refs
25694 if(this.firstChild == node){
25695 this.setFirstChild(node.nextSibling);
25697 if(this.lastChild == node){
25698 this.setLastChild(node.previousSibling);
25701 node.setOwnerTree(null);
25702 // clear any references from the node
25703 node.parentNode = null;
25704 node.previousSibling = null;
25705 node.nextSibling = null;
25706 this.fireEvent("remove", this.ownerTree, this, node);
25711 * Inserts the first node before the second node in this nodes childNodes collection.
25712 * @param {Node} node The node to insert
25713 * @param {Node} refNode The node to insert before (if null the node is appended)
25714 * @return {Node} The inserted node
25716 insertBefore : function(node, refNode){
25717 if(!refNode){ // like standard Dom, refNode can be null for append
25718 return this.appendChild(node);
25721 if(node == refNode){
25725 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25728 var index = this.childNodes.indexOf(refNode);
25729 var oldParent = node.parentNode;
25730 var refIndex = index;
25732 // when moving internally, indexes will change after remove
25733 if(oldParent == this && this.childNodes.indexOf(node) < index){
25737 // it's a move, make sure we move it cleanly
25739 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25742 oldParent.removeChild(node);
25745 this.setFirstChild(node);
25747 this.childNodes.splice(refIndex, 0, node);
25748 node.parentNode = this;
25749 var ps = this.childNodes[refIndex-1];
25751 node.previousSibling = ps;
25752 ps.nextSibling = node;
25754 node.previousSibling = null;
25756 node.nextSibling = refNode;
25757 refNode.previousSibling = node;
25758 node.setOwnerTree(this.getOwnerTree());
25759 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25761 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25767 * Returns the child node at the specified index.
25768 * @param {Number} index
25771 item : function(index){
25772 return this.childNodes[index];
25776 * Replaces one child node in this node with another.
25777 * @param {Node} newChild The replacement node
25778 * @param {Node} oldChild The node to replace
25779 * @return {Node} The replaced node
25781 replaceChild : function(newChild, oldChild){
25782 this.insertBefore(newChild, oldChild);
25783 this.removeChild(oldChild);
25788 * Returns the index of a child node
25789 * @param {Node} node
25790 * @return {Number} The index of the node or -1 if it was not found
25792 indexOf : function(child){
25793 return this.childNodes.indexOf(child);
25797 * Returns the tree this node is in.
25800 getOwnerTree : function(){
25801 // if it doesn't have one, look for one
25802 if(!this.ownerTree){
25806 this.ownerTree = p.ownerTree;
25812 return this.ownerTree;
25816 * Returns depth of this node (the root node has a depth of 0)
25819 getDepth : function(){
25822 while(p.parentNode){
25830 setOwnerTree : function(tree){
25831 // if it's move, we need to update everyone
25832 if(tree != this.ownerTree){
25833 if(this.ownerTree){
25834 this.ownerTree.unregisterNode(this);
25836 this.ownerTree = tree;
25837 var cs = this.childNodes;
25838 for(var i = 0, len = cs.length; i < len; i++) {
25839 cs[i].setOwnerTree(tree);
25842 tree.registerNode(this);
25848 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25849 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25850 * @return {String} The path
25852 getPath : function(attr){
25853 attr = attr || "id";
25854 var p = this.parentNode;
25855 var b = [this.attributes[attr]];
25857 b.unshift(p.attributes[attr]);
25860 var sep = this.getOwnerTree().pathSeparator;
25861 return sep + b.join(sep);
25865 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25866 * function call will be the scope provided or the current node. The arguments to the function
25867 * will be the args provided or the current node. If the function returns false at any point,
25868 * the bubble is stopped.
25869 * @param {Function} fn The function to call
25870 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25871 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25873 bubble : function(fn, scope, args){
25876 if(fn.call(scope || p, args || p) === false){
25884 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25885 * function call will be the scope provided or the current node. The arguments to the function
25886 * will be the args provided or the current node. If the function returns false at any point,
25887 * the cascade is stopped on that branch.
25888 * @param {Function} fn The function to call
25889 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25890 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25892 cascade : function(fn, scope, args){
25893 if(fn.call(scope || this, args || this) !== false){
25894 var cs = this.childNodes;
25895 for(var i = 0, len = cs.length; i < len; i++) {
25896 cs[i].cascade(fn, scope, args);
25902 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25903 * function call will be the scope provided or the current node. The arguments to the function
25904 * will be the args provided or the current node. If the function returns false at any point,
25905 * the iteration stops.
25906 * @param {Function} fn The function to call
25907 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25908 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25910 eachChild : function(fn, scope, args){
25911 var cs = this.childNodes;
25912 for(var i = 0, len = cs.length; i < len; i++) {
25913 if(fn.call(scope || this, args || cs[i]) === false){
25920 * Finds the first child that has the attribute with the specified value.
25921 * @param {String} attribute The attribute name
25922 * @param {Mixed} value The value to search for
25923 * @return {Node} The found child or null if none was found
25925 findChild : function(attribute, value){
25926 var cs = this.childNodes;
25927 for(var i = 0, len = cs.length; i < len; i++) {
25928 if(cs[i].attributes[attribute] == value){
25936 * Finds the first child by a custom function. The child matches if the function passed
25938 * @param {Function} fn
25939 * @param {Object} scope (optional)
25940 * @return {Node} The found child or null if none was found
25942 findChildBy : function(fn, scope){
25943 var cs = this.childNodes;
25944 for(var i = 0, len = cs.length; i < len; i++) {
25945 if(fn.call(scope||cs[i], cs[i]) === true){
25953 * Sorts this nodes children using the supplied sort function
25954 * @param {Function} fn
25955 * @param {Object} scope (optional)
25957 sort : function(fn, scope){
25958 var cs = this.childNodes;
25959 var len = cs.length;
25961 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25963 for(var i = 0; i < len; i++){
25965 n.previousSibling = cs[i-1];
25966 n.nextSibling = cs[i+1];
25968 this.setFirstChild(n);
25971 this.setLastChild(n);
25978 * Returns true if this node is an ancestor (at any point) of the passed node.
25979 * @param {Node} node
25980 * @return {Boolean}
25982 contains : function(node){
25983 return node.isAncestor(this);
25987 * Returns true if the passed node is an ancestor (at any point) of this node.
25988 * @param {Node} node
25989 * @return {Boolean}
25991 isAncestor : function(node){
25992 var p = this.parentNode;
26002 toString : function(){
26003 return "[Node"+(this.id?" "+this.id:"")+"]";
26007 * Ext JS Library 1.1.1
26008 * Copyright(c) 2006-2007, Ext JS, LLC.
26010 * Originally Released Under LGPL - original licence link has changed is not relivant.
26013 * <script type="text/javascript">
26018 * @class Roo.Shadow
26019 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26020 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26021 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26023 * Create a new Shadow
26024 * @param {Object} config The config object
26026 Roo.Shadow = function(config){
26027 Roo.apply(this, config);
26028 if(typeof this.mode != "string"){
26029 this.mode = this.defaultMode;
26031 var o = this.offset, a = {h: 0};
26032 var rad = Math.floor(this.offset/2);
26033 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26039 a.l -= this.offset + rad;
26040 a.t -= this.offset + rad;
26051 a.l -= (this.offset - rad);
26052 a.t -= this.offset + rad;
26054 a.w -= (this.offset - rad)*2;
26065 a.l -= (this.offset - rad);
26066 a.t -= (this.offset - rad);
26068 a.w -= (this.offset + rad + 1);
26069 a.h -= (this.offset + rad);
26078 Roo.Shadow.prototype = {
26080 * @cfg {String} mode
26081 * The shadow display mode. Supports the following options:<br />
26082 * sides: Shadow displays on both sides and bottom only<br />
26083 * frame: Shadow displays equally on all four sides<br />
26084 * drop: Traditional bottom-right drop shadow (default)
26087 * @cfg {String} offset
26088 * The number of pixels to offset the shadow from the element (defaults to 4)
26093 defaultMode: "drop",
26096 * Displays the shadow under the target element
26097 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26099 show : function(target){
26100 target = Roo.get(target);
26102 this.el = Roo.Shadow.Pool.pull();
26103 if(this.el.dom.nextSibling != target.dom){
26104 this.el.insertBefore(target);
26107 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26109 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26112 target.getLeft(true),
26113 target.getTop(true),
26117 this.el.dom.style.display = "block";
26121 * Returns true if the shadow is visible, else false
26123 isVisible : function(){
26124 return this.el ? true : false;
26128 * Direct alignment when values are already available. Show must be called at least once before
26129 * calling this method to ensure it is initialized.
26130 * @param {Number} left The target element left position
26131 * @param {Number} top The target element top position
26132 * @param {Number} width The target element width
26133 * @param {Number} height The target element height
26135 realign : function(l, t, w, h){
26139 var a = this.adjusts, d = this.el.dom, s = d.style;
26141 s.left = (l+a.l)+"px";
26142 s.top = (t+a.t)+"px";
26143 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26145 if(s.width != sws || s.height != shs){
26149 var cn = d.childNodes;
26150 var sww = Math.max(0, (sw-12))+"px";
26151 cn[0].childNodes[1].style.width = sww;
26152 cn[1].childNodes[1].style.width = sww;
26153 cn[2].childNodes[1].style.width = sww;
26154 cn[1].style.height = Math.max(0, (sh-12))+"px";
26160 * Hides this shadow
26164 this.el.dom.style.display = "none";
26165 Roo.Shadow.Pool.push(this.el);
26171 * Adjust the z-index of this shadow
26172 * @param {Number} zindex The new z-index
26174 setZIndex : function(z){
26177 this.el.setStyle("z-index", z);
26182 // Private utility class that manages the internal Shadow cache
26183 Roo.Shadow.Pool = function(){
26185 var markup = Roo.isIE ?
26186 '<div class="x-ie-shadow"></div>' :
26187 '<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>';
26190 var sh = p.shift();
26192 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26193 sh.autoBoxAdjust = false;
26198 push : function(sh){
26204 * Ext JS Library 1.1.1
26205 * Copyright(c) 2006-2007, Ext JS, LLC.
26207 * Originally Released Under LGPL - original licence link has changed is not relivant.
26210 * <script type="text/javascript">
26215 * @class Roo.SplitBar
26216 * @extends Roo.util.Observable
26217 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26221 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26222 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26223 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26224 split.minSize = 100;
26225 split.maxSize = 600;
26226 split.animate = true;
26227 split.on('moved', splitterMoved);
26230 * Create a new SplitBar
26231 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26232 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26233 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26234 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26235 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26236 position of the SplitBar).
26238 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26241 this.el = Roo.get(dragElement, true);
26242 this.el.dom.unselectable = "on";
26244 this.resizingEl = Roo.get(resizingElement, true);
26248 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26249 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26252 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26255 * The minimum size of the resizing element. (Defaults to 0)
26261 * The maximum size of the resizing element. (Defaults to 2000)
26264 this.maxSize = 2000;
26267 * Whether to animate the transition to the new size
26270 this.animate = false;
26273 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26276 this.useShim = false;
26281 if(!existingProxy){
26283 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26285 this.proxy = Roo.get(existingProxy).dom;
26288 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26291 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26294 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26297 this.dragSpecs = {};
26300 * @private The adapter to use to positon and resize elements
26302 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26303 this.adapter.init(this);
26305 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26307 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26308 this.el.addClass("x-splitbar-h");
26311 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26312 this.el.addClass("x-splitbar-v");
26318 * Fires when the splitter is moved (alias for {@link #event-moved})
26319 * @param {Roo.SplitBar} this
26320 * @param {Number} newSize the new width or height
26325 * Fires when the splitter is moved
26326 * @param {Roo.SplitBar} this
26327 * @param {Number} newSize the new width or height
26331 * @event beforeresize
26332 * Fires before the splitter is dragged
26333 * @param {Roo.SplitBar} this
26335 "beforeresize" : true,
26337 "beforeapply" : true
26340 Roo.util.Observable.call(this);
26343 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26344 onStartProxyDrag : function(x, y){
26345 this.fireEvent("beforeresize", this);
26347 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26349 o.enableDisplayMode("block");
26350 // all splitbars share the same overlay
26351 Roo.SplitBar.prototype.overlay = o;
26353 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26354 this.overlay.show();
26355 Roo.get(this.proxy).setDisplayed("block");
26356 var size = this.adapter.getElementSize(this);
26357 this.activeMinSize = this.getMinimumSize();;
26358 this.activeMaxSize = this.getMaximumSize();;
26359 var c1 = size - this.activeMinSize;
26360 var c2 = Math.max(this.activeMaxSize - size, 0);
26361 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26362 this.dd.resetConstraints();
26363 this.dd.setXConstraint(
26364 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26365 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26367 this.dd.setYConstraint(0, 0);
26369 this.dd.resetConstraints();
26370 this.dd.setXConstraint(0, 0);
26371 this.dd.setYConstraint(
26372 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26373 this.placement == Roo.SplitBar.TOP ? c2 : c1
26376 this.dragSpecs.startSize = size;
26377 this.dragSpecs.startPoint = [x, y];
26378 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26382 * @private Called after the drag operation by the DDProxy
26384 onEndProxyDrag : function(e){
26385 Roo.get(this.proxy).setDisplayed(false);
26386 var endPoint = Roo.lib.Event.getXY(e);
26388 this.overlay.hide();
26391 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26392 newSize = this.dragSpecs.startSize +
26393 (this.placement == Roo.SplitBar.LEFT ?
26394 endPoint[0] - this.dragSpecs.startPoint[0] :
26395 this.dragSpecs.startPoint[0] - endPoint[0]
26398 newSize = this.dragSpecs.startSize +
26399 (this.placement == Roo.SplitBar.TOP ?
26400 endPoint[1] - this.dragSpecs.startPoint[1] :
26401 this.dragSpecs.startPoint[1] - endPoint[1]
26404 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26405 if(newSize != this.dragSpecs.startSize){
26406 if(this.fireEvent('beforeapply', this, newSize) !== false){
26407 this.adapter.setElementSize(this, newSize);
26408 this.fireEvent("moved", this, newSize);
26409 this.fireEvent("resize", this, newSize);
26415 * Get the adapter this SplitBar uses
26416 * @return The adapter object
26418 getAdapter : function(){
26419 return this.adapter;
26423 * Set the adapter this SplitBar uses
26424 * @param {Object} adapter A SplitBar adapter object
26426 setAdapter : function(adapter){
26427 this.adapter = adapter;
26428 this.adapter.init(this);
26432 * Gets the minimum size for the resizing element
26433 * @return {Number} The minimum size
26435 getMinimumSize : function(){
26436 return this.minSize;
26440 * Sets the minimum size for the resizing element
26441 * @param {Number} minSize The minimum size
26443 setMinimumSize : function(minSize){
26444 this.minSize = minSize;
26448 * Gets the maximum size for the resizing element
26449 * @return {Number} The maximum size
26451 getMaximumSize : function(){
26452 return this.maxSize;
26456 * Sets the maximum size for the resizing element
26457 * @param {Number} maxSize The maximum size
26459 setMaximumSize : function(maxSize){
26460 this.maxSize = maxSize;
26464 * Sets the initialize size for the resizing element
26465 * @param {Number} size The initial size
26467 setCurrentSize : function(size){
26468 var oldAnimate = this.animate;
26469 this.animate = false;
26470 this.adapter.setElementSize(this, size);
26471 this.animate = oldAnimate;
26475 * Destroy this splitbar.
26476 * @param {Boolean} removeEl True to remove the element
26478 destroy : function(removeEl){
26480 this.shim.remove();
26483 this.proxy.parentNode.removeChild(this.proxy);
26491 * @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.
26493 Roo.SplitBar.createProxy = function(dir){
26494 var proxy = new Roo.Element(document.createElement("div"));
26495 proxy.unselectable();
26496 var cls = 'x-splitbar-proxy';
26497 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26498 document.body.appendChild(proxy.dom);
26503 * @class Roo.SplitBar.BasicLayoutAdapter
26504 * Default Adapter. It assumes the splitter and resizing element are not positioned
26505 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26507 Roo.SplitBar.BasicLayoutAdapter = function(){
26510 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26511 // do nothing for now
26512 init : function(s){
26516 * Called before drag operations to get the current size of the resizing element.
26517 * @param {Roo.SplitBar} s The SplitBar using this adapter
26519 getElementSize : function(s){
26520 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26521 return s.resizingEl.getWidth();
26523 return s.resizingEl.getHeight();
26528 * Called after drag operations to set the size of the resizing element.
26529 * @param {Roo.SplitBar} s The SplitBar using this adapter
26530 * @param {Number} newSize The new size to set
26531 * @param {Function} onComplete A function to be invoked when resizing is complete
26533 setElementSize : function(s, newSize, onComplete){
26534 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26536 s.resizingEl.setWidth(newSize);
26538 onComplete(s, newSize);
26541 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26546 s.resizingEl.setHeight(newSize);
26548 onComplete(s, newSize);
26551 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26558 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26559 * @extends Roo.SplitBar.BasicLayoutAdapter
26560 * Adapter that moves the splitter element to align with the resized sizing element.
26561 * Used with an absolute positioned SplitBar.
26562 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26563 * document.body, make sure you assign an id to the body element.
26565 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26566 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26567 this.container = Roo.get(container);
26570 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26571 init : function(s){
26572 this.basic.init(s);
26575 getElementSize : function(s){
26576 return this.basic.getElementSize(s);
26579 setElementSize : function(s, newSize, onComplete){
26580 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26583 moveSplitter : function(s){
26584 var yes = Roo.SplitBar;
26585 switch(s.placement){
26587 s.el.setX(s.resizingEl.getRight());
26590 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26593 s.el.setY(s.resizingEl.getBottom());
26596 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26603 * Orientation constant - Create a vertical SplitBar
26607 Roo.SplitBar.VERTICAL = 1;
26610 * Orientation constant - Create a horizontal SplitBar
26614 Roo.SplitBar.HORIZONTAL = 2;
26617 * Placement constant - The resizing element is to the left of the splitter element
26621 Roo.SplitBar.LEFT = 1;
26624 * Placement constant - The resizing element is to the right of the splitter element
26628 Roo.SplitBar.RIGHT = 2;
26631 * Placement constant - The resizing element is positioned above the splitter element
26635 Roo.SplitBar.TOP = 3;
26638 * Placement constant - The resizing element is positioned under splitter element
26642 Roo.SplitBar.BOTTOM = 4;
26645 * Ext JS Library 1.1.1
26646 * Copyright(c) 2006-2007, Ext JS, LLC.
26648 * Originally Released Under LGPL - original licence link has changed is not relivant.
26651 * <script type="text/javascript">
26656 * @extends Roo.util.Observable
26657 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26658 * This class also supports single and multi selection modes. <br>
26659 * Create a data model bound view:
26661 var store = new Roo.data.Store(...);
26663 var view = new Roo.View({
26665 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26667 singleSelect: true,
26668 selectedClass: "ydataview-selected",
26672 // listen for node click?
26673 view.on("click", function(vw, index, node, e){
26674 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26678 dataModel.load("foobar.xml");
26680 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26682 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26683 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26685 * Note: old style constructor is still suported (container, template, config)
26688 * Create a new View
26689 * @param {Object} config The config object
26692 Roo.View = function(config, depreciated_tpl, depreciated_config){
26694 this.parent = false;
26696 if (typeof(depreciated_tpl) == 'undefined') {
26697 // new way.. - universal constructor.
26698 Roo.apply(this, config);
26699 this.el = Roo.get(this.el);
26702 this.el = Roo.get(config);
26703 this.tpl = depreciated_tpl;
26704 Roo.apply(this, depreciated_config);
26706 this.wrapEl = this.el.wrap().wrap();
26707 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26710 if(typeof(this.tpl) == "string"){
26711 this.tpl = new Roo.Template(this.tpl);
26713 // support xtype ctors..
26714 this.tpl = new Roo.factory(this.tpl, Roo);
26718 this.tpl.compile();
26723 * @event beforeclick
26724 * Fires before a click is processed. Returns false to cancel the default action.
26725 * @param {Roo.View} this
26726 * @param {Number} index The index of the target node
26727 * @param {HTMLElement} node The target node
26728 * @param {Roo.EventObject} e The raw event object
26730 "beforeclick" : true,
26733 * Fires when a template node is clicked.
26734 * @param {Roo.View} this
26735 * @param {Number} index The index of the target node
26736 * @param {HTMLElement} node The target node
26737 * @param {Roo.EventObject} e The raw event object
26742 * Fires when a template node is double clicked.
26743 * @param {Roo.View} this
26744 * @param {Number} index The index of the target node
26745 * @param {HTMLElement} node The target node
26746 * @param {Roo.EventObject} e The raw event object
26750 * @event contextmenu
26751 * Fires when a template node is right clicked.
26752 * @param {Roo.View} this
26753 * @param {Number} index The index of the target node
26754 * @param {HTMLElement} node The target node
26755 * @param {Roo.EventObject} e The raw event object
26757 "contextmenu" : true,
26759 * @event selectionchange
26760 * Fires when the selected nodes change.
26761 * @param {Roo.View} this
26762 * @param {Array} selections Array of the selected nodes
26764 "selectionchange" : true,
26767 * @event beforeselect
26768 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26769 * @param {Roo.View} this
26770 * @param {HTMLElement} node The node to be selected
26771 * @param {Array} selections Array of currently selected nodes
26773 "beforeselect" : true,
26775 * @event preparedata
26776 * Fires on every row to render, to allow you to change the data.
26777 * @param {Roo.View} this
26778 * @param {Object} data to be rendered (change this)
26780 "preparedata" : true
26788 "click": this.onClick,
26789 "dblclick": this.onDblClick,
26790 "contextmenu": this.onContextMenu,
26794 this.selections = [];
26796 this.cmp = new Roo.CompositeElementLite([]);
26798 this.store = Roo.factory(this.store, Roo.data);
26799 this.setStore(this.store, true);
26802 if ( this.footer && this.footer.xtype) {
26804 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26806 this.footer.dataSource = this.store;
26807 this.footer.container = fctr;
26808 this.footer = Roo.factory(this.footer, Roo);
26809 fctr.insertFirst(this.el);
26811 // this is a bit insane - as the paging toolbar seems to detach the el..
26812 // dom.parentNode.parentNode.parentNode
26813 // they get detached?
26817 Roo.View.superclass.constructor.call(this);
26822 Roo.extend(Roo.View, Roo.util.Observable, {
26825 * @cfg {Roo.data.Store} store Data store to load data from.
26830 * @cfg {String|Roo.Element} el The container element.
26835 * @cfg {String|Roo.Template} tpl The template used by this View
26839 * @cfg {String} dataName the named area of the template to use as the data area
26840 * Works with domtemplates roo-name="name"
26844 * @cfg {String} selectedClass The css class to add to selected nodes
26846 selectedClass : "x-view-selected",
26848 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26853 * @cfg {String} text to display on mask (default Loading)
26857 * @cfg {Boolean} multiSelect Allow multiple selection
26859 multiSelect : false,
26861 * @cfg {Boolean} singleSelect Allow single selection
26863 singleSelect: false,
26866 * @cfg {Boolean} toggleSelect - selecting
26868 toggleSelect : false,
26871 * @cfg {Boolean} tickable - selecting
26876 * Returns the element this view is bound to.
26877 * @return {Roo.Element}
26879 getEl : function(){
26880 return this.wrapEl;
26886 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26888 refresh : function(){
26889 //Roo.log('refresh');
26892 // if we are using something like 'domtemplate', then
26893 // the what gets used is:
26894 // t.applySubtemplate(NAME, data, wrapping data..)
26895 // the outer template then get' applied with
26896 // the store 'extra data'
26897 // and the body get's added to the
26898 // roo-name="data" node?
26899 // <span class='roo-tpl-{name}'></span> ?????
26903 this.clearSelections();
26904 this.el.update("");
26906 var records = this.store.getRange();
26907 if(records.length < 1) {
26909 // is this valid?? = should it render a template??
26911 this.el.update(this.emptyText);
26915 if (this.dataName) {
26916 this.el.update(t.apply(this.store.meta)); //????
26917 el = this.el.child('.roo-tpl-' + this.dataName);
26920 for(var i = 0, len = records.length; i < len; i++){
26921 var data = this.prepareData(records[i].data, i, records[i]);
26922 this.fireEvent("preparedata", this, data, i, records[i]);
26924 var d = Roo.apply({}, data);
26927 Roo.apply(d, {'roo-id' : Roo.id()});
26931 Roo.each(this.parent.item, function(item){
26932 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26935 Roo.apply(d, {'roo-data-checked' : 'checked'});
26939 html[html.length] = Roo.util.Format.trim(
26941 t.applySubtemplate(this.dataName, d, this.store.meta) :
26948 el.update(html.join(""));
26949 this.nodes = el.dom.childNodes;
26950 this.updateIndexes(0);
26955 * Function to override to reformat the data that is sent to
26956 * the template for each node.
26957 * DEPRICATED - use the preparedata event handler.
26958 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26959 * a JSON object for an UpdateManager bound view).
26961 prepareData : function(data, index, record)
26963 this.fireEvent("preparedata", this, data, index, record);
26967 onUpdate : function(ds, record){
26968 // Roo.log('on update');
26969 this.clearSelections();
26970 var index = this.store.indexOf(record);
26971 var n = this.nodes[index];
26972 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26973 n.parentNode.removeChild(n);
26974 this.updateIndexes(index, index);
26980 onAdd : function(ds, records, index)
26982 //Roo.log(['on Add', ds, records, index] );
26983 this.clearSelections();
26984 if(this.nodes.length == 0){
26988 var n = this.nodes[index];
26989 for(var i = 0, len = records.length; i < len; i++){
26990 var d = this.prepareData(records[i].data, i, records[i]);
26992 this.tpl.insertBefore(n, d);
26995 this.tpl.append(this.el, d);
26998 this.updateIndexes(index);
27001 onRemove : function(ds, record, index){
27002 // Roo.log('onRemove');
27003 this.clearSelections();
27004 var el = this.dataName ?
27005 this.el.child('.roo-tpl-' + this.dataName) :
27008 el.dom.removeChild(this.nodes[index]);
27009 this.updateIndexes(index);
27013 * Refresh an individual node.
27014 * @param {Number} index
27016 refreshNode : function(index){
27017 this.onUpdate(this.store, this.store.getAt(index));
27020 updateIndexes : function(startIndex, endIndex){
27021 var ns = this.nodes;
27022 startIndex = startIndex || 0;
27023 endIndex = endIndex || ns.length - 1;
27024 for(var i = startIndex; i <= endIndex; i++){
27025 ns[i].nodeIndex = i;
27030 * Changes the data store this view uses and refresh the view.
27031 * @param {Store} store
27033 setStore : function(store, initial){
27034 if(!initial && this.store){
27035 this.store.un("datachanged", this.refresh);
27036 this.store.un("add", this.onAdd);
27037 this.store.un("remove", this.onRemove);
27038 this.store.un("update", this.onUpdate);
27039 this.store.un("clear", this.refresh);
27040 this.store.un("beforeload", this.onBeforeLoad);
27041 this.store.un("load", this.onLoad);
27042 this.store.un("loadexception", this.onLoad);
27046 store.on("datachanged", this.refresh, this);
27047 store.on("add", this.onAdd, this);
27048 store.on("remove", this.onRemove, this);
27049 store.on("update", this.onUpdate, this);
27050 store.on("clear", this.refresh, this);
27051 store.on("beforeload", this.onBeforeLoad, this);
27052 store.on("load", this.onLoad, this);
27053 store.on("loadexception", this.onLoad, this);
27061 * onbeforeLoad - masks the loading area.
27064 onBeforeLoad : function(store,opts)
27066 //Roo.log('onBeforeLoad');
27068 this.el.update("");
27070 this.el.mask(this.mask ? this.mask : "Loading" );
27072 onLoad : function ()
27079 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27080 * @param {HTMLElement} node
27081 * @return {HTMLElement} The template node
27083 findItemFromChild : function(node){
27084 var el = this.dataName ?
27085 this.el.child('.roo-tpl-' + this.dataName,true) :
27088 if(!node || node.parentNode == el){
27091 var p = node.parentNode;
27092 while(p && p != el){
27093 if(p.parentNode == el){
27102 onClick : function(e){
27103 var item = this.findItemFromChild(e.getTarget());
27105 var index = this.indexOf(item);
27106 if(this.onItemClick(item, index, e) !== false){
27107 this.fireEvent("click", this, index, item, e);
27110 this.clearSelections();
27115 onContextMenu : function(e){
27116 var item = this.findItemFromChild(e.getTarget());
27118 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27123 onDblClick : function(e){
27124 var item = this.findItemFromChild(e.getTarget());
27126 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27130 onItemClick : function(item, index, e)
27132 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27135 if (this.toggleSelect) {
27136 var m = this.isSelected(item) ? 'unselect' : 'select';
27139 _t[m](item, true, false);
27142 if(this.multiSelect || this.singleSelect){
27143 if(this.multiSelect && e.shiftKey && this.lastSelection){
27144 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27146 this.select(item, this.multiSelect && e.ctrlKey);
27147 this.lastSelection = item;
27150 if(!this.tickable){
27151 e.preventDefault();
27159 * Get the number of selected nodes.
27162 getSelectionCount : function(){
27163 return this.selections.length;
27167 * Get the currently selected nodes.
27168 * @return {Array} An array of HTMLElements
27170 getSelectedNodes : function(){
27171 return this.selections;
27175 * Get the indexes of the selected nodes.
27178 getSelectedIndexes : function(){
27179 var indexes = [], s = this.selections;
27180 for(var i = 0, len = s.length; i < len; i++){
27181 indexes.push(s[i].nodeIndex);
27187 * Clear all selections
27188 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27190 clearSelections : function(suppressEvent){
27191 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27192 this.cmp.elements = this.selections;
27193 this.cmp.removeClass(this.selectedClass);
27194 this.selections = [];
27195 if(!suppressEvent){
27196 this.fireEvent("selectionchange", this, this.selections);
27202 * Returns true if the passed node is selected
27203 * @param {HTMLElement/Number} node The node or node index
27204 * @return {Boolean}
27206 isSelected : function(node){
27207 var s = this.selections;
27211 node = this.getNode(node);
27212 return s.indexOf(node) !== -1;
27217 * @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
27218 * @param {Boolean} keepExisting (optional) true to keep existing selections
27219 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27221 select : function(nodeInfo, keepExisting, suppressEvent){
27222 if(nodeInfo instanceof Array){
27224 this.clearSelections(true);
27226 for(var i = 0, len = nodeInfo.length; i < len; i++){
27227 this.select(nodeInfo[i], true, true);
27231 var node = this.getNode(nodeInfo);
27232 if(!node || this.isSelected(node)){
27233 return; // already selected.
27236 this.clearSelections(true);
27239 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27240 Roo.fly(node).addClass(this.selectedClass);
27241 this.selections.push(node);
27242 if(!suppressEvent){
27243 this.fireEvent("selectionchange", this, this.selections);
27251 * @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
27252 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27253 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27255 unselect : function(nodeInfo, keepExisting, suppressEvent)
27257 if(nodeInfo instanceof Array){
27258 Roo.each(this.selections, function(s) {
27259 this.unselect(s, nodeInfo);
27263 var node = this.getNode(nodeInfo);
27264 if(!node || !this.isSelected(node)){
27265 //Roo.log("not selected");
27266 return; // not selected.
27270 Roo.each(this.selections, function(s) {
27272 Roo.fly(node).removeClass(this.selectedClass);
27279 this.selections= ns;
27280 this.fireEvent("selectionchange", this, this.selections);
27284 * Gets a template node.
27285 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27286 * @return {HTMLElement} The node or null if it wasn't found
27288 getNode : function(nodeInfo){
27289 if(typeof nodeInfo == "string"){
27290 return document.getElementById(nodeInfo);
27291 }else if(typeof nodeInfo == "number"){
27292 return this.nodes[nodeInfo];
27298 * Gets a range template nodes.
27299 * @param {Number} startIndex
27300 * @param {Number} endIndex
27301 * @return {Array} An array of nodes
27303 getNodes : function(start, end){
27304 var ns = this.nodes;
27305 start = start || 0;
27306 end = typeof end == "undefined" ? ns.length - 1 : end;
27309 for(var i = start; i <= end; i++){
27313 for(var i = start; i >= end; i--){
27321 * Finds the index of the passed node
27322 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27323 * @return {Number} The index of the node or -1
27325 indexOf : function(node){
27326 node = this.getNode(node);
27327 if(typeof node.nodeIndex == "number"){
27328 return node.nodeIndex;
27330 var ns = this.nodes;
27331 for(var i = 0, len = ns.length; i < len; i++){
27341 * Ext JS Library 1.1.1
27342 * Copyright(c) 2006-2007, Ext JS, LLC.
27344 * Originally Released Under LGPL - original licence link has changed is not relivant.
27347 * <script type="text/javascript">
27351 * @class Roo.JsonView
27352 * @extends Roo.View
27353 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27355 var view = new Roo.JsonView({
27356 container: "my-element",
27357 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27362 // listen for node click?
27363 view.on("click", function(vw, index, node, e){
27364 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27367 // direct load of JSON data
27368 view.load("foobar.php");
27370 // Example from my blog list
27371 var tpl = new Roo.Template(
27372 '<div class="entry">' +
27373 '<a class="entry-title" href="{link}">{title}</a>' +
27374 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27375 "</div><hr />"
27378 var moreView = new Roo.JsonView({
27379 container : "entry-list",
27383 moreView.on("beforerender", this.sortEntries, this);
27385 url: "/blog/get-posts.php",
27386 params: "allposts=true",
27387 text: "Loading Blog Entries..."
27391 * Note: old code is supported with arguments : (container, template, config)
27395 * Create a new JsonView
27397 * @param {Object} config The config object
27400 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27403 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27405 var um = this.el.getUpdateManager();
27406 um.setRenderer(this);
27407 um.on("update", this.onLoad, this);
27408 um.on("failure", this.onLoadException, this);
27411 * @event beforerender
27412 * Fires before rendering of the downloaded JSON data.
27413 * @param {Roo.JsonView} this
27414 * @param {Object} data The JSON data loaded
27418 * Fires when data is loaded.
27419 * @param {Roo.JsonView} this
27420 * @param {Object} data The JSON data loaded
27421 * @param {Object} response The raw Connect response object
27424 * @event loadexception
27425 * Fires when loading fails.
27426 * @param {Roo.JsonView} this
27427 * @param {Object} response The raw Connect response object
27430 'beforerender' : true,
27432 'loadexception' : true
27435 Roo.extend(Roo.JsonView, Roo.View, {
27437 * @type {String} The root property in the loaded JSON object that contains the data
27442 * Refreshes the view.
27444 refresh : function(){
27445 this.clearSelections();
27446 this.el.update("");
27448 var o = this.jsonData;
27449 if(o && o.length > 0){
27450 for(var i = 0, len = o.length; i < len; i++){
27451 var data = this.prepareData(o[i], i, o);
27452 html[html.length] = this.tpl.apply(data);
27455 html.push(this.emptyText);
27457 this.el.update(html.join(""));
27458 this.nodes = this.el.dom.childNodes;
27459 this.updateIndexes(0);
27463 * 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.
27464 * @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:
27467 url: "your-url.php",
27468 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27469 callback: yourFunction,
27470 scope: yourObject, //(optional scope)
27473 text: "Loading...",
27478 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27479 * 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.
27480 * @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}
27481 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27482 * @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.
27485 var um = this.el.getUpdateManager();
27486 um.update.apply(um, arguments);
27489 // note - render is a standard framework call...
27490 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27491 render : function(el, response){
27493 this.clearSelections();
27494 this.el.update("");
27497 if (response != '') {
27498 o = Roo.util.JSON.decode(response.responseText);
27501 o = o[this.jsonRoot];
27507 * The current JSON data or null
27510 this.beforeRender();
27515 * Get the number of records in the current JSON dataset
27518 getCount : function(){
27519 return this.jsonData ? this.jsonData.length : 0;
27523 * Returns the JSON object for the specified node(s)
27524 * @param {HTMLElement/Array} node The node or an array of nodes
27525 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27526 * you get the JSON object for the node
27528 getNodeData : function(node){
27529 if(node instanceof Array){
27531 for(var i = 0, len = node.length; i < len; i++){
27532 data.push(this.getNodeData(node[i]));
27536 return this.jsonData[this.indexOf(node)] || null;
27539 beforeRender : function(){
27540 this.snapshot = this.jsonData;
27542 this.sort.apply(this, this.sortInfo);
27544 this.fireEvent("beforerender", this, this.jsonData);
27547 onLoad : function(el, o){
27548 this.fireEvent("load", this, this.jsonData, o);
27551 onLoadException : function(el, o){
27552 this.fireEvent("loadexception", this, o);
27556 * Filter the data by a specific property.
27557 * @param {String} property A property on your JSON objects
27558 * @param {String/RegExp} value Either string that the property values
27559 * should start with, or a RegExp to test against the property
27561 filter : function(property, value){
27564 var ss = this.snapshot;
27565 if(typeof value == "string"){
27566 var vlen = value.length;
27568 this.clearFilter();
27571 value = value.toLowerCase();
27572 for(var i = 0, len = ss.length; i < len; i++){
27574 if(o[property].substr(0, vlen).toLowerCase() == value){
27578 } else if(value.exec){ // regex?
27579 for(var i = 0, len = ss.length; i < len; i++){
27581 if(value.test(o[property])){
27588 this.jsonData = data;
27594 * Filter by a function. The passed function will be called with each
27595 * object in the current dataset. If the function returns true the value is kept,
27596 * otherwise it is filtered.
27597 * @param {Function} fn
27598 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27600 filterBy : function(fn, scope){
27603 var ss = this.snapshot;
27604 for(var i = 0, len = ss.length; i < len; i++){
27606 if(fn.call(scope || this, o)){
27610 this.jsonData = data;
27616 * Clears the current filter.
27618 clearFilter : function(){
27619 if(this.snapshot && this.jsonData != this.snapshot){
27620 this.jsonData = this.snapshot;
27627 * Sorts the data for this view and refreshes it.
27628 * @param {String} property A property on your JSON objects to sort on
27629 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27630 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27632 sort : function(property, dir, sortType){
27633 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27636 var dsc = dir && dir.toLowerCase() == "desc";
27637 var f = function(o1, o2){
27638 var v1 = sortType ? sortType(o1[p]) : o1[p];
27639 var v2 = sortType ? sortType(o2[p]) : o2[p];
27642 return dsc ? +1 : -1;
27643 } else if(v1 > v2){
27644 return dsc ? -1 : +1;
27649 this.jsonData.sort(f);
27651 if(this.jsonData != this.snapshot){
27652 this.snapshot.sort(f);
27658 * Ext JS Library 1.1.1
27659 * Copyright(c) 2006-2007, Ext JS, LLC.
27661 * Originally Released Under LGPL - original licence link has changed is not relivant.
27664 * <script type="text/javascript">
27669 * @class Roo.ColorPalette
27670 * @extends Roo.Component
27671 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27672 * Here's an example of typical usage:
27674 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27675 cp.render('my-div');
27677 cp.on('select', function(palette, selColor){
27678 // do something with selColor
27682 * Create a new ColorPalette
27683 * @param {Object} config The config object
27685 Roo.ColorPalette = function(config){
27686 Roo.ColorPalette.superclass.constructor.call(this, config);
27690 * Fires when a color is selected
27691 * @param {ColorPalette} this
27692 * @param {String} color The 6-digit color hex code (without the # symbol)
27698 this.on("select", this.handler, this.scope, true);
27701 Roo.extend(Roo.ColorPalette, Roo.Component, {
27703 * @cfg {String} itemCls
27704 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27706 itemCls : "x-color-palette",
27708 * @cfg {String} value
27709 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27710 * the hex codes are case-sensitive.
27713 clickEvent:'click',
27715 ctype: "Roo.ColorPalette",
27718 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27720 allowReselect : false,
27723 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27724 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27725 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27726 * of colors with the width setting until the box is symmetrical.</p>
27727 * <p>You can override individual colors if needed:</p>
27729 var cp = new Roo.ColorPalette();
27730 cp.colors[0] = "FF0000"; // change the first box to red
27733 Or you can provide a custom array of your own for complete control:
27735 var cp = new Roo.ColorPalette();
27736 cp.colors = ["000000", "993300", "333300"];
27741 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27742 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27743 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27744 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27745 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27749 onRender : function(container, position){
27750 var t = new Roo.MasterTemplate(
27751 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27753 var c = this.colors;
27754 for(var i = 0, len = c.length; i < len; i++){
27757 var el = document.createElement("div");
27758 el.className = this.itemCls;
27760 container.dom.insertBefore(el, position);
27761 this.el = Roo.get(el);
27762 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27763 if(this.clickEvent != 'click'){
27764 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27769 afterRender : function(){
27770 Roo.ColorPalette.superclass.afterRender.call(this);
27772 var s = this.value;
27779 handleClick : function(e, t){
27780 e.preventDefault();
27781 if(!this.disabled){
27782 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27783 this.select(c.toUpperCase());
27788 * Selects the specified color in the palette (fires the select event)
27789 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27791 select : function(color){
27792 color = color.replace("#", "");
27793 if(color != this.value || this.allowReselect){
27796 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27798 el.child("a.color-"+color).addClass("x-color-palette-sel");
27799 this.value = color;
27800 this.fireEvent("select", this, color);
27805 * Ext JS Library 1.1.1
27806 * Copyright(c) 2006-2007, Ext JS, LLC.
27808 * Originally Released Under LGPL - original licence link has changed is not relivant.
27811 * <script type="text/javascript">
27815 * @class Roo.DatePicker
27816 * @extends Roo.Component
27817 * Simple date picker class.
27819 * Create a new DatePicker
27820 * @param {Object} config The config object
27822 Roo.DatePicker = function(config){
27823 Roo.DatePicker.superclass.constructor.call(this, config);
27825 this.value = config && config.value ?
27826 config.value.clearTime() : new Date().clearTime();
27831 * Fires when a date is selected
27832 * @param {DatePicker} this
27833 * @param {Date} date The selected date
27837 * @event monthchange
27838 * Fires when the displayed month changes
27839 * @param {DatePicker} this
27840 * @param {Date} date The selected month
27842 'monthchange': true
27846 this.on("select", this.handler, this.scope || this);
27848 // build the disabledDatesRE
27849 if(!this.disabledDatesRE && this.disabledDates){
27850 var dd = this.disabledDates;
27852 for(var i = 0; i < dd.length; i++){
27854 if(i != dd.length-1) {
27858 this.disabledDatesRE = new RegExp(re + ")");
27862 Roo.extend(Roo.DatePicker, Roo.Component, {
27864 * @cfg {String} todayText
27865 * The text to display on the button that selects the current date (defaults to "Today")
27867 todayText : "Today",
27869 * @cfg {String} okText
27870 * The text to display on the ok button
27872 okText : " OK ", //   to give the user extra clicking room
27874 * @cfg {String} cancelText
27875 * The text to display on the cancel button
27877 cancelText : "Cancel",
27879 * @cfg {String} todayTip
27880 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27882 todayTip : "{0} (Spacebar)",
27884 * @cfg {Date} minDate
27885 * Minimum allowable date (JavaScript date object, defaults to null)
27889 * @cfg {Date} maxDate
27890 * Maximum allowable date (JavaScript date object, defaults to null)
27894 * @cfg {String} minText
27895 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27897 minText : "This date is before the minimum date",
27899 * @cfg {String} maxText
27900 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27902 maxText : "This date is after the maximum date",
27904 * @cfg {String} format
27905 * The default date format string which can be overriden for localization support. The format must be
27906 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27910 * @cfg {Array} disabledDays
27911 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27913 disabledDays : null,
27915 * @cfg {String} disabledDaysText
27916 * The tooltip to display when the date falls on a disabled day (defaults to "")
27918 disabledDaysText : "",
27920 * @cfg {RegExp} disabledDatesRE
27921 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27923 disabledDatesRE : null,
27925 * @cfg {String} disabledDatesText
27926 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27928 disabledDatesText : "",
27930 * @cfg {Boolean} constrainToViewport
27931 * True to constrain the date picker to the viewport (defaults to true)
27933 constrainToViewport : true,
27935 * @cfg {Array} monthNames
27936 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27938 monthNames : Date.monthNames,
27940 * @cfg {Array} dayNames
27941 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27943 dayNames : Date.dayNames,
27945 * @cfg {String} nextText
27946 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27948 nextText: 'Next Month (Control+Right)',
27950 * @cfg {String} prevText
27951 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27953 prevText: 'Previous Month (Control+Left)',
27955 * @cfg {String} monthYearText
27956 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27958 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27960 * @cfg {Number} startDay
27961 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27965 * @cfg {Bool} showClear
27966 * Show a clear button (usefull for date form elements that can be blank.)
27972 * Sets the value of the date field
27973 * @param {Date} value The date to set
27975 setValue : function(value){
27976 var old = this.value;
27978 if (typeof(value) == 'string') {
27980 value = Date.parseDate(value, this.format);
27983 value = new Date();
27986 this.value = value.clearTime(true);
27988 this.update(this.value);
27993 * Gets the current selected value of the date field
27994 * @return {Date} The selected date
27996 getValue : function(){
28001 focus : function(){
28003 this.update(this.activeDate);
28008 onRender : function(container, position){
28011 '<table cellspacing="0">',
28012 '<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>',
28013 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28014 var dn = this.dayNames;
28015 for(var i = 0; i < 7; i++){
28016 var d = this.startDay+i;
28020 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28022 m[m.length] = "</tr></thead><tbody><tr>";
28023 for(var i = 0; i < 42; i++) {
28024 if(i % 7 == 0 && i != 0){
28025 m[m.length] = "</tr><tr>";
28027 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28029 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28030 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28032 var el = document.createElement("div");
28033 el.className = "x-date-picker";
28034 el.innerHTML = m.join("");
28036 container.dom.insertBefore(el, position);
28038 this.el = Roo.get(el);
28039 this.eventEl = Roo.get(el.firstChild);
28041 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28042 handler: this.showPrevMonth,
28044 preventDefault:true,
28048 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28049 handler: this.showNextMonth,
28051 preventDefault:true,
28055 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28057 this.monthPicker = this.el.down('div.x-date-mp');
28058 this.monthPicker.enableDisplayMode('block');
28060 var kn = new Roo.KeyNav(this.eventEl, {
28061 "left" : function(e){
28063 this.showPrevMonth() :
28064 this.update(this.activeDate.add("d", -1));
28067 "right" : function(e){
28069 this.showNextMonth() :
28070 this.update(this.activeDate.add("d", 1));
28073 "up" : function(e){
28075 this.showNextYear() :
28076 this.update(this.activeDate.add("d", -7));
28079 "down" : function(e){
28081 this.showPrevYear() :
28082 this.update(this.activeDate.add("d", 7));
28085 "pageUp" : function(e){
28086 this.showNextMonth();
28089 "pageDown" : function(e){
28090 this.showPrevMonth();
28093 "enter" : function(e){
28094 e.stopPropagation();
28101 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28103 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28105 this.el.unselectable();
28107 this.cells = this.el.select("table.x-date-inner tbody td");
28108 this.textNodes = this.el.query("table.x-date-inner tbody span");
28110 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28112 tooltip: this.monthYearText
28115 this.mbtn.on('click', this.showMonthPicker, this);
28116 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28119 var today = (new Date()).dateFormat(this.format);
28121 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28122 if (this.showClear) {
28123 baseTb.add( new Roo.Toolbar.Fill());
28126 text: String.format(this.todayText, today),
28127 tooltip: String.format(this.todayTip, today),
28128 handler: this.selectToday,
28132 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28135 if (this.showClear) {
28137 baseTb.add( new Roo.Toolbar.Fill());
28140 cls: 'x-btn-icon x-btn-clear',
28141 handler: function() {
28143 this.fireEvent("select", this, '');
28153 this.update(this.value);
28156 createMonthPicker : function(){
28157 if(!this.monthPicker.dom.firstChild){
28158 var buf = ['<table border="0" cellspacing="0">'];
28159 for(var i = 0; i < 6; i++){
28161 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28162 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28164 '<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>' :
28165 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28169 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28171 '</button><button type="button" class="x-date-mp-cancel">',
28173 '</button></td></tr>',
28176 this.monthPicker.update(buf.join(''));
28177 this.monthPicker.on('click', this.onMonthClick, this);
28178 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28180 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28181 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28183 this.mpMonths.each(function(m, a, i){
28186 m.dom.xmonth = 5 + Math.round(i * .5);
28188 m.dom.xmonth = Math.round((i-1) * .5);
28194 showMonthPicker : function(){
28195 this.createMonthPicker();
28196 var size = this.el.getSize();
28197 this.monthPicker.setSize(size);
28198 this.monthPicker.child('table').setSize(size);
28200 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28201 this.updateMPMonth(this.mpSelMonth);
28202 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28203 this.updateMPYear(this.mpSelYear);
28205 this.monthPicker.slideIn('t', {duration:.2});
28208 updateMPYear : function(y){
28210 var ys = this.mpYears.elements;
28211 for(var i = 1; i <= 10; i++){
28212 var td = ys[i-1], y2;
28214 y2 = y + Math.round(i * .5);
28215 td.firstChild.innerHTML = y2;
28218 y2 = y - (5-Math.round(i * .5));
28219 td.firstChild.innerHTML = y2;
28222 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28226 updateMPMonth : function(sm){
28227 this.mpMonths.each(function(m, a, i){
28228 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28232 selectMPMonth: function(m){
28236 onMonthClick : function(e, t){
28238 var el = new Roo.Element(t), pn;
28239 if(el.is('button.x-date-mp-cancel')){
28240 this.hideMonthPicker();
28242 else if(el.is('button.x-date-mp-ok')){
28243 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28244 this.hideMonthPicker();
28246 else if(pn = el.up('td.x-date-mp-month', 2)){
28247 this.mpMonths.removeClass('x-date-mp-sel');
28248 pn.addClass('x-date-mp-sel');
28249 this.mpSelMonth = pn.dom.xmonth;
28251 else if(pn = el.up('td.x-date-mp-year', 2)){
28252 this.mpYears.removeClass('x-date-mp-sel');
28253 pn.addClass('x-date-mp-sel');
28254 this.mpSelYear = pn.dom.xyear;
28256 else if(el.is('a.x-date-mp-prev')){
28257 this.updateMPYear(this.mpyear-10);
28259 else if(el.is('a.x-date-mp-next')){
28260 this.updateMPYear(this.mpyear+10);
28264 onMonthDblClick : function(e, t){
28266 var el = new Roo.Element(t), pn;
28267 if(pn = el.up('td.x-date-mp-month', 2)){
28268 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28269 this.hideMonthPicker();
28271 else if(pn = el.up('td.x-date-mp-year', 2)){
28272 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28273 this.hideMonthPicker();
28277 hideMonthPicker : function(disableAnim){
28278 if(this.monthPicker){
28279 if(disableAnim === true){
28280 this.monthPicker.hide();
28282 this.monthPicker.slideOut('t', {duration:.2});
28288 showPrevMonth : function(e){
28289 this.update(this.activeDate.add("mo", -1));
28293 showNextMonth : function(e){
28294 this.update(this.activeDate.add("mo", 1));
28298 showPrevYear : function(){
28299 this.update(this.activeDate.add("y", -1));
28303 showNextYear : function(){
28304 this.update(this.activeDate.add("y", 1));
28308 handleMouseWheel : function(e){
28309 var delta = e.getWheelDelta();
28311 this.showPrevMonth();
28313 } else if(delta < 0){
28314 this.showNextMonth();
28320 handleDateClick : function(e, t){
28322 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28323 this.setValue(new Date(t.dateValue));
28324 this.fireEvent("select", this, this.value);
28329 selectToday : function(){
28330 this.setValue(new Date().clearTime());
28331 this.fireEvent("select", this, this.value);
28335 update : function(date)
28337 var vd = this.activeDate;
28338 this.activeDate = date;
28340 var t = date.getTime();
28341 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28342 this.cells.removeClass("x-date-selected");
28343 this.cells.each(function(c){
28344 if(c.dom.firstChild.dateValue == t){
28345 c.addClass("x-date-selected");
28346 setTimeout(function(){
28347 try{c.dom.firstChild.focus();}catch(e){}
28356 var days = date.getDaysInMonth();
28357 var firstOfMonth = date.getFirstDateOfMonth();
28358 var startingPos = firstOfMonth.getDay()-this.startDay;
28360 if(startingPos <= this.startDay){
28364 var pm = date.add("mo", -1);
28365 var prevStart = pm.getDaysInMonth()-startingPos;
28367 var cells = this.cells.elements;
28368 var textEls = this.textNodes;
28369 days += startingPos;
28371 // convert everything to numbers so it's fast
28372 var day = 86400000;
28373 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28374 var today = new Date().clearTime().getTime();
28375 var sel = date.clearTime().getTime();
28376 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28377 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28378 var ddMatch = this.disabledDatesRE;
28379 var ddText = this.disabledDatesText;
28380 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28381 var ddaysText = this.disabledDaysText;
28382 var format = this.format;
28384 var setCellClass = function(cal, cell){
28386 var t = d.getTime();
28387 cell.firstChild.dateValue = t;
28389 cell.className += " x-date-today";
28390 cell.title = cal.todayText;
28393 cell.className += " x-date-selected";
28394 setTimeout(function(){
28395 try{cell.firstChild.focus();}catch(e){}
28400 cell.className = " x-date-disabled";
28401 cell.title = cal.minText;
28405 cell.className = " x-date-disabled";
28406 cell.title = cal.maxText;
28410 if(ddays.indexOf(d.getDay()) != -1){
28411 cell.title = ddaysText;
28412 cell.className = " x-date-disabled";
28415 if(ddMatch && format){
28416 var fvalue = d.dateFormat(format);
28417 if(ddMatch.test(fvalue)){
28418 cell.title = ddText.replace("%0", fvalue);
28419 cell.className = " x-date-disabled";
28425 for(; i < startingPos; i++) {
28426 textEls[i].innerHTML = (++prevStart);
28427 d.setDate(d.getDate()+1);
28428 cells[i].className = "x-date-prevday";
28429 setCellClass(this, cells[i]);
28431 for(; i < days; i++){
28432 intDay = i - startingPos + 1;
28433 textEls[i].innerHTML = (intDay);
28434 d.setDate(d.getDate()+1);
28435 cells[i].className = "x-date-active";
28436 setCellClass(this, cells[i]);
28439 for(; i < 42; i++) {
28440 textEls[i].innerHTML = (++extraDays);
28441 d.setDate(d.getDate()+1);
28442 cells[i].className = "x-date-nextday";
28443 setCellClass(this, cells[i]);
28446 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28447 this.fireEvent('monthchange', this, date);
28449 if(!this.internalRender){
28450 var main = this.el.dom.firstChild;
28451 var w = main.offsetWidth;
28452 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28453 Roo.fly(main).setWidth(w);
28454 this.internalRender = true;
28455 // opera does not respect the auto grow header center column
28456 // then, after it gets a width opera refuses to recalculate
28457 // without a second pass
28458 if(Roo.isOpera && !this.secondPass){
28459 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28460 this.secondPass = true;
28461 this.update.defer(10, this, [date]);
28469 * Ext JS Library 1.1.1
28470 * Copyright(c) 2006-2007, Ext JS, LLC.
28472 * Originally Released Under LGPL - original licence link has changed is not relivant.
28475 * <script type="text/javascript">
28478 * @class Roo.TabPanel
28479 * @extends Roo.util.Observable
28480 * A lightweight tab container.
28484 // basic tabs 1, built from existing content
28485 var tabs = new Roo.TabPanel("tabs1");
28486 tabs.addTab("script", "View Script");
28487 tabs.addTab("markup", "View Markup");
28488 tabs.activate("script");
28490 // more advanced tabs, built from javascript
28491 var jtabs = new Roo.TabPanel("jtabs");
28492 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28494 // set up the UpdateManager
28495 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28496 var updater = tab2.getUpdateManager();
28497 updater.setDefaultUrl("ajax1.htm");
28498 tab2.on('activate', updater.refresh, updater, true);
28500 // Use setUrl for Ajax loading
28501 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28502 tab3.setUrl("ajax2.htm", null, true);
28505 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28508 jtabs.activate("jtabs-1");
28511 * Create a new TabPanel.
28512 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28513 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28515 Roo.TabPanel = function(container, config){
28517 * The container element for this TabPanel.
28518 * @type Roo.Element
28520 this.el = Roo.get(container, true);
28522 if(typeof config == "boolean"){
28523 this.tabPosition = config ? "bottom" : "top";
28525 Roo.apply(this, config);
28528 if(this.tabPosition == "bottom"){
28529 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28530 this.el.addClass("x-tabs-bottom");
28532 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28533 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28534 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28536 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28538 if(this.tabPosition != "bottom"){
28539 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28540 * @type Roo.Element
28542 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28543 this.el.addClass("x-tabs-top");
28547 this.bodyEl.setStyle("position", "relative");
28549 this.active = null;
28550 this.activateDelegate = this.activate.createDelegate(this);
28555 * Fires when the active tab changes
28556 * @param {Roo.TabPanel} this
28557 * @param {Roo.TabPanelItem} activePanel The new active tab
28561 * @event beforetabchange
28562 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28563 * @param {Roo.TabPanel} this
28564 * @param {Object} e Set cancel to true on this object to cancel the tab change
28565 * @param {Roo.TabPanelItem} tab The tab being changed to
28567 "beforetabchange" : true
28570 Roo.EventManager.onWindowResize(this.onResize, this);
28571 this.cpad = this.el.getPadding("lr");
28572 this.hiddenCount = 0;
28575 // toolbar on the tabbar support...
28576 if (this.toolbar) {
28577 var tcfg = this.toolbar;
28578 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28579 this.toolbar = new Roo.Toolbar(tcfg);
28580 if (Roo.isSafari) {
28581 var tbl = tcfg.container.child('table', true);
28582 tbl.setAttribute('width', '100%');
28589 Roo.TabPanel.superclass.constructor.call(this);
28592 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28594 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28596 tabPosition : "top",
28598 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28600 currentTabWidth : 0,
28602 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28606 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28610 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28612 preferredTabWidth : 175,
28614 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28616 resizeTabs : false,
28618 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28620 monitorResize : true,
28622 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28627 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28628 * @param {String} id The id of the div to use <b>or create</b>
28629 * @param {String} text The text for the tab
28630 * @param {String} content (optional) Content to put in the TabPanelItem body
28631 * @param {Boolean} closable (optional) True to create a close icon on the tab
28632 * @return {Roo.TabPanelItem} The created TabPanelItem
28634 addTab : function(id, text, content, closable){
28635 var item = new Roo.TabPanelItem(this, id, text, closable);
28636 this.addTabItem(item);
28638 item.setContent(content);
28644 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28645 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28646 * @return {Roo.TabPanelItem}
28648 getTab : function(id){
28649 return this.items[id];
28653 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28654 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28656 hideTab : function(id){
28657 var t = this.items[id];
28660 this.hiddenCount++;
28661 this.autoSizeTabs();
28666 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28667 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28669 unhideTab : function(id){
28670 var t = this.items[id];
28672 t.setHidden(false);
28673 this.hiddenCount--;
28674 this.autoSizeTabs();
28679 * Adds an existing {@link Roo.TabPanelItem}.
28680 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28682 addTabItem : function(item){
28683 this.items[item.id] = item;
28684 this.items.push(item);
28685 if(this.resizeTabs){
28686 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28687 this.autoSizeTabs();
28694 * Removes a {@link Roo.TabPanelItem}.
28695 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28697 removeTab : function(id){
28698 var items = this.items;
28699 var tab = items[id];
28700 if(!tab) { return; }
28701 var index = items.indexOf(tab);
28702 if(this.active == tab && items.length > 1){
28703 var newTab = this.getNextAvailable(index);
28708 this.stripEl.dom.removeChild(tab.pnode.dom);
28709 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28710 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28712 items.splice(index, 1);
28713 delete this.items[tab.id];
28714 tab.fireEvent("close", tab);
28715 tab.purgeListeners();
28716 this.autoSizeTabs();
28719 getNextAvailable : function(start){
28720 var items = this.items;
28722 // look for a next tab that will slide over to
28723 // replace the one being removed
28724 while(index < items.length){
28725 var item = items[++index];
28726 if(item && !item.isHidden()){
28730 // if one isn't found select the previous tab (on the left)
28733 var item = items[--index];
28734 if(item && !item.isHidden()){
28742 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28743 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28745 disableTab : function(id){
28746 var tab = this.items[id];
28747 if(tab && this.active != tab){
28753 * Enables a {@link Roo.TabPanelItem} that is disabled.
28754 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28756 enableTab : function(id){
28757 var tab = this.items[id];
28762 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28763 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28764 * @return {Roo.TabPanelItem} The TabPanelItem.
28766 activate : function(id){
28767 var tab = this.items[id];
28771 if(tab == this.active || tab.disabled){
28775 this.fireEvent("beforetabchange", this, e, tab);
28776 if(e.cancel !== true && !tab.disabled){
28778 this.active.hide();
28780 this.active = this.items[id];
28781 this.active.show();
28782 this.fireEvent("tabchange", this, this.active);
28788 * Gets the active {@link Roo.TabPanelItem}.
28789 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28791 getActiveTab : function(){
28792 return this.active;
28796 * Updates the tab body element to fit the height of the container element
28797 * for overflow scrolling
28798 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28800 syncHeight : function(targetHeight){
28801 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28802 var bm = this.bodyEl.getMargins();
28803 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28804 this.bodyEl.setHeight(newHeight);
28808 onResize : function(){
28809 if(this.monitorResize){
28810 this.autoSizeTabs();
28815 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28817 beginUpdate : function(){
28818 this.updating = true;
28822 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28824 endUpdate : function(){
28825 this.updating = false;
28826 this.autoSizeTabs();
28830 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28832 autoSizeTabs : function(){
28833 var count = this.items.length;
28834 var vcount = count - this.hiddenCount;
28835 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28838 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28839 var availWidth = Math.floor(w / vcount);
28840 var b = this.stripBody;
28841 if(b.getWidth() > w){
28842 var tabs = this.items;
28843 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28844 if(availWidth < this.minTabWidth){
28845 /*if(!this.sleft){ // incomplete scrolling code
28846 this.createScrollButtons();
28849 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28852 if(this.currentTabWidth < this.preferredTabWidth){
28853 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28859 * Returns the number of tabs in this TabPanel.
28862 getCount : function(){
28863 return this.items.length;
28867 * Resizes all the tabs to the passed width
28868 * @param {Number} The new width
28870 setTabWidth : function(width){
28871 this.currentTabWidth = width;
28872 for(var i = 0, len = this.items.length; i < len; i++) {
28873 if(!this.items[i].isHidden()) {
28874 this.items[i].setWidth(width);
28880 * Destroys this TabPanel
28881 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28883 destroy : function(removeEl){
28884 Roo.EventManager.removeResizeListener(this.onResize, this);
28885 for(var i = 0, len = this.items.length; i < len; i++){
28886 this.items[i].purgeListeners();
28888 if(removeEl === true){
28889 this.el.update("");
28896 * @class Roo.TabPanelItem
28897 * @extends Roo.util.Observable
28898 * Represents an individual item (tab plus body) in a TabPanel.
28899 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28900 * @param {String} id The id of this TabPanelItem
28901 * @param {String} text The text for the tab of this TabPanelItem
28902 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28904 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28906 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28907 * @type Roo.TabPanel
28909 this.tabPanel = tabPanel;
28911 * The id for this TabPanelItem
28916 this.disabled = false;
28920 this.loaded = false;
28921 this.closable = closable;
28924 * The body element for this TabPanelItem.
28925 * @type Roo.Element
28927 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28928 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28929 this.bodyEl.setStyle("display", "block");
28930 this.bodyEl.setStyle("zoom", "1");
28933 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28935 this.el = Roo.get(els.el, true);
28936 this.inner = Roo.get(els.inner, true);
28937 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28938 this.pnode = Roo.get(els.el.parentNode, true);
28939 this.el.on("mousedown", this.onTabMouseDown, this);
28940 this.el.on("click", this.onTabClick, this);
28943 var c = Roo.get(els.close, true);
28944 c.dom.title = this.closeText;
28945 c.addClassOnOver("close-over");
28946 c.on("click", this.closeClick, this);
28952 * Fires when this tab becomes the active tab.
28953 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28954 * @param {Roo.TabPanelItem} this
28958 * @event beforeclose
28959 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28960 * @param {Roo.TabPanelItem} this
28961 * @param {Object} e Set cancel to true on this object to cancel the close.
28963 "beforeclose": true,
28966 * Fires when this tab is closed.
28967 * @param {Roo.TabPanelItem} this
28971 * @event deactivate
28972 * Fires when this tab is no longer the active tab.
28973 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28974 * @param {Roo.TabPanelItem} this
28976 "deactivate" : true
28978 this.hidden = false;
28980 Roo.TabPanelItem.superclass.constructor.call(this);
28983 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28984 purgeListeners : function(){
28985 Roo.util.Observable.prototype.purgeListeners.call(this);
28986 this.el.removeAllListeners();
28989 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28992 this.pnode.addClass("on");
28995 this.tabPanel.stripWrap.repaint();
28997 this.fireEvent("activate", this.tabPanel, this);
29001 * Returns true if this tab is the active tab.
29002 * @return {Boolean}
29004 isActive : function(){
29005 return this.tabPanel.getActiveTab() == this;
29009 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29012 this.pnode.removeClass("on");
29014 this.fireEvent("deactivate", this.tabPanel, this);
29017 hideAction : function(){
29018 this.bodyEl.hide();
29019 this.bodyEl.setStyle("position", "absolute");
29020 this.bodyEl.setLeft("-20000px");
29021 this.bodyEl.setTop("-20000px");
29024 showAction : function(){
29025 this.bodyEl.setStyle("position", "relative");
29026 this.bodyEl.setTop("");
29027 this.bodyEl.setLeft("");
29028 this.bodyEl.show();
29032 * Set the tooltip for the tab.
29033 * @param {String} tooltip The tab's tooltip
29035 setTooltip : function(text){
29036 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29037 this.textEl.dom.qtip = text;
29038 this.textEl.dom.removeAttribute('title');
29040 this.textEl.dom.title = text;
29044 onTabClick : function(e){
29045 e.preventDefault();
29046 this.tabPanel.activate(this.id);
29049 onTabMouseDown : function(e){
29050 e.preventDefault();
29051 this.tabPanel.activate(this.id);
29054 getWidth : function(){
29055 return this.inner.getWidth();
29058 setWidth : function(width){
29059 var iwidth = width - this.pnode.getPadding("lr");
29060 this.inner.setWidth(iwidth);
29061 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29062 this.pnode.setWidth(width);
29066 * Show or hide the tab
29067 * @param {Boolean} hidden True to hide or false to show.
29069 setHidden : function(hidden){
29070 this.hidden = hidden;
29071 this.pnode.setStyle("display", hidden ? "none" : "");
29075 * Returns true if this tab is "hidden"
29076 * @return {Boolean}
29078 isHidden : function(){
29079 return this.hidden;
29083 * Returns the text for this tab
29086 getText : function(){
29090 autoSize : function(){
29091 //this.el.beginMeasure();
29092 this.textEl.setWidth(1);
29094 * #2804 [new] Tabs in Roojs
29095 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29097 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29098 //this.el.endMeasure();
29102 * Sets the text for the tab (Note: this also sets the tooltip text)
29103 * @param {String} text The tab's text and tooltip
29105 setText : function(text){
29107 this.textEl.update(text);
29108 this.setTooltip(text);
29109 if(!this.tabPanel.resizeTabs){
29114 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29116 activate : function(){
29117 this.tabPanel.activate(this.id);
29121 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29123 disable : function(){
29124 if(this.tabPanel.active != this){
29125 this.disabled = true;
29126 this.pnode.addClass("disabled");
29131 * Enables this TabPanelItem if it was previously disabled.
29133 enable : function(){
29134 this.disabled = false;
29135 this.pnode.removeClass("disabled");
29139 * Sets the content for this TabPanelItem.
29140 * @param {String} content The content
29141 * @param {Boolean} loadScripts true to look for and load scripts
29143 setContent : function(content, loadScripts){
29144 this.bodyEl.update(content, loadScripts);
29148 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29149 * @return {Roo.UpdateManager} The UpdateManager
29151 getUpdateManager : function(){
29152 return this.bodyEl.getUpdateManager();
29156 * Set a URL to be used to load the content for this TabPanelItem.
29157 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29158 * @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)
29159 * @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)
29160 * @return {Roo.UpdateManager} The UpdateManager
29162 setUrl : function(url, params, loadOnce){
29163 if(this.refreshDelegate){
29164 this.un('activate', this.refreshDelegate);
29166 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29167 this.on("activate", this.refreshDelegate);
29168 return this.bodyEl.getUpdateManager();
29172 _handleRefresh : function(url, params, loadOnce){
29173 if(!loadOnce || !this.loaded){
29174 var updater = this.bodyEl.getUpdateManager();
29175 updater.update(url, params, this._setLoaded.createDelegate(this));
29180 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29181 * Will fail silently if the setUrl method has not been called.
29182 * This does not activate the panel, just updates its content.
29184 refresh : function(){
29185 if(this.refreshDelegate){
29186 this.loaded = false;
29187 this.refreshDelegate();
29192 _setLoaded : function(){
29193 this.loaded = true;
29197 closeClick : function(e){
29200 this.fireEvent("beforeclose", this, o);
29201 if(o.cancel !== true){
29202 this.tabPanel.removeTab(this.id);
29206 * The text displayed in the tooltip for the close icon.
29209 closeText : "Close this tab"
29213 Roo.TabPanel.prototype.createStrip = function(container){
29214 var strip = document.createElement("div");
29215 strip.className = "x-tabs-wrap";
29216 container.appendChild(strip);
29220 Roo.TabPanel.prototype.createStripList = function(strip){
29221 // div wrapper for retard IE
29222 // returns the "tr" element.
29223 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29224 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29225 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29226 return strip.firstChild.firstChild.firstChild.firstChild;
29229 Roo.TabPanel.prototype.createBody = function(container){
29230 var body = document.createElement("div");
29231 Roo.id(body, "tab-body");
29232 Roo.fly(body).addClass("x-tabs-body");
29233 container.appendChild(body);
29237 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29238 var body = Roo.getDom(id);
29240 body = document.createElement("div");
29243 Roo.fly(body).addClass("x-tabs-item-body");
29244 bodyEl.insertBefore(body, bodyEl.firstChild);
29248 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29249 var td = document.createElement("td");
29250 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29251 //stripEl.appendChild(td);
29253 td.className = "x-tabs-closable";
29254 if(!this.closeTpl){
29255 this.closeTpl = new Roo.Template(
29256 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29257 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29258 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29261 var el = this.closeTpl.overwrite(td, {"text": text});
29262 var close = el.getElementsByTagName("div")[0];
29263 var inner = el.getElementsByTagName("em")[0];
29264 return {"el": el, "close": close, "inner": inner};
29267 this.tabTpl = new Roo.Template(
29268 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29269 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29272 var el = this.tabTpl.overwrite(td, {"text": text});
29273 var inner = el.getElementsByTagName("em")[0];
29274 return {"el": el, "inner": inner};
29278 * Ext JS Library 1.1.1
29279 * Copyright(c) 2006-2007, Ext JS, LLC.
29281 * Originally Released Under LGPL - original licence link has changed is not relivant.
29284 * <script type="text/javascript">
29288 * @class Roo.Button
29289 * @extends Roo.util.Observable
29290 * Simple Button class
29291 * @cfg {String} text The button text
29292 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29293 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29294 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29295 * @cfg {Object} scope The scope of the handler
29296 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29297 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29298 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29299 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29300 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29301 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29302 applies if enableToggle = true)
29303 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29304 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29305 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29307 * Create a new button
29308 * @param {Object} config The config object
29310 Roo.Button = function(renderTo, config)
29314 renderTo = config.renderTo || false;
29317 Roo.apply(this, config);
29321 * Fires when this button is clicked
29322 * @param {Button} this
29323 * @param {EventObject} e The click event
29328 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29329 * @param {Button} this
29330 * @param {Boolean} pressed
29335 * Fires when the mouse hovers over the button
29336 * @param {Button} this
29337 * @param {Event} e The event object
29339 'mouseover' : true,
29342 * Fires when the mouse exits the button
29343 * @param {Button} this
29344 * @param {Event} e The event object
29349 * Fires when the button is rendered
29350 * @param {Button} this
29355 this.menu = Roo.menu.MenuMgr.get(this.menu);
29357 // register listeners first!! - so render can be captured..
29358 Roo.util.Observable.call(this);
29360 this.render(renderTo);
29366 Roo.extend(Roo.Button, Roo.util.Observable, {
29372 * Read-only. True if this button is hidden
29377 * Read-only. True if this button is disabled
29382 * Read-only. True if this button is pressed (only if enableToggle = true)
29388 * @cfg {Number} tabIndex
29389 * The DOM tabIndex for this button (defaults to undefined)
29391 tabIndex : undefined,
29394 * @cfg {Boolean} enableToggle
29395 * True to enable pressed/not pressed toggling (defaults to false)
29397 enableToggle: false,
29399 * @cfg {Mixed} menu
29400 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29404 * @cfg {String} menuAlign
29405 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29407 menuAlign : "tl-bl?",
29410 * @cfg {String} iconCls
29411 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29413 iconCls : undefined,
29415 * @cfg {String} type
29416 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29421 menuClassTarget: 'tr',
29424 * @cfg {String} clickEvent
29425 * The type of event to map to the button's event handler (defaults to 'click')
29427 clickEvent : 'click',
29430 * @cfg {Boolean} handleMouseEvents
29431 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29433 handleMouseEvents : true,
29436 * @cfg {String} tooltipType
29437 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29439 tooltipType : 'qtip',
29442 * @cfg {String} cls
29443 * A CSS class to apply to the button's main element.
29447 * @cfg {Roo.Template} template (Optional)
29448 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29449 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29450 * require code modifications if required elements (e.g. a button) aren't present.
29454 render : function(renderTo){
29456 if(this.hideParent){
29457 this.parentEl = Roo.get(renderTo);
29459 if(!this.dhconfig){
29460 if(!this.template){
29461 if(!Roo.Button.buttonTemplate){
29462 // hideous table template
29463 Roo.Button.buttonTemplate = new Roo.Template(
29464 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29465 '<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>',
29466 "</tr></tbody></table>");
29468 this.template = Roo.Button.buttonTemplate;
29470 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29471 var btnEl = btn.child("button:first");
29472 btnEl.on('focus', this.onFocus, this);
29473 btnEl.on('blur', this.onBlur, this);
29475 btn.addClass(this.cls);
29478 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29481 btnEl.addClass(this.iconCls);
29483 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29486 if(this.tabIndex !== undefined){
29487 btnEl.dom.tabIndex = this.tabIndex;
29490 if(typeof this.tooltip == 'object'){
29491 Roo.QuickTips.tips(Roo.apply({
29495 btnEl.dom[this.tooltipType] = this.tooltip;
29499 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29503 this.el.dom.id = this.el.id = this.id;
29506 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29507 this.menu.on("show", this.onMenuShow, this);
29508 this.menu.on("hide", this.onMenuHide, this);
29510 btn.addClass("x-btn");
29511 if(Roo.isIE && !Roo.isIE7){
29512 this.autoWidth.defer(1, this);
29516 if(this.handleMouseEvents){
29517 btn.on("mouseover", this.onMouseOver, this);
29518 btn.on("mouseout", this.onMouseOut, this);
29519 btn.on("mousedown", this.onMouseDown, this);
29521 btn.on(this.clickEvent, this.onClick, this);
29522 //btn.on("mouseup", this.onMouseUp, this);
29529 Roo.ButtonToggleMgr.register(this);
29531 this.el.addClass("x-btn-pressed");
29534 var repeater = new Roo.util.ClickRepeater(btn,
29535 typeof this.repeat == "object" ? this.repeat : {}
29537 repeater.on("click", this.onClick, this);
29540 this.fireEvent('render', this);
29544 * Returns the button's underlying element
29545 * @return {Roo.Element} The element
29547 getEl : function(){
29552 * Destroys this Button and removes any listeners.
29554 destroy : function(){
29555 Roo.ButtonToggleMgr.unregister(this);
29556 this.el.removeAllListeners();
29557 this.purgeListeners();
29562 autoWidth : function(){
29564 this.el.setWidth("auto");
29565 if(Roo.isIE7 && Roo.isStrict){
29566 var ib = this.el.child('button');
29567 if(ib && ib.getWidth() > 20){
29569 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29574 this.el.beginMeasure();
29576 if(this.el.getWidth() < this.minWidth){
29577 this.el.setWidth(this.minWidth);
29580 this.el.endMeasure();
29587 * Assigns this button's click handler
29588 * @param {Function} handler The function to call when the button is clicked
29589 * @param {Object} scope (optional) Scope for the function passed in
29591 setHandler : function(handler, scope){
29592 this.handler = handler;
29593 this.scope = scope;
29597 * Sets this button's text
29598 * @param {String} text The button text
29600 setText : function(text){
29603 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29609 * Gets the text for this button
29610 * @return {String} The button text
29612 getText : function(){
29620 this.hidden = false;
29622 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29630 this.hidden = true;
29632 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29637 * Convenience function for boolean show/hide
29638 * @param {Boolean} visible True to show, false to hide
29640 setVisible: function(visible){
29649 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29650 * @param {Boolean} state (optional) Force a particular state
29652 toggle : function(state){
29653 state = state === undefined ? !this.pressed : state;
29654 if(state != this.pressed){
29656 this.el.addClass("x-btn-pressed");
29657 this.pressed = true;
29658 this.fireEvent("toggle", this, true);
29660 this.el.removeClass("x-btn-pressed");
29661 this.pressed = false;
29662 this.fireEvent("toggle", this, false);
29664 if(this.toggleHandler){
29665 this.toggleHandler.call(this.scope || this, this, state);
29673 focus : function(){
29674 this.el.child('button:first').focus();
29678 * Disable this button
29680 disable : function(){
29682 this.el.addClass("x-btn-disabled");
29684 this.disabled = true;
29688 * Enable this button
29690 enable : function(){
29692 this.el.removeClass("x-btn-disabled");
29694 this.disabled = false;
29698 * Convenience function for boolean enable/disable
29699 * @param {Boolean} enabled True to enable, false to disable
29701 setDisabled : function(v){
29702 this[v !== true ? "enable" : "disable"]();
29706 onClick : function(e)
29709 e.preventDefault();
29714 if(!this.disabled){
29715 if(this.enableToggle){
29718 if(this.menu && !this.menu.isVisible()){
29719 this.menu.show(this.el, this.menuAlign);
29721 this.fireEvent("click", this, e);
29723 this.el.removeClass("x-btn-over");
29724 this.handler.call(this.scope || this, this, e);
29729 onMouseOver : function(e){
29730 if(!this.disabled){
29731 this.el.addClass("x-btn-over");
29732 this.fireEvent('mouseover', this, e);
29736 onMouseOut : function(e){
29737 if(!e.within(this.el, true)){
29738 this.el.removeClass("x-btn-over");
29739 this.fireEvent('mouseout', this, e);
29743 onFocus : function(e){
29744 if(!this.disabled){
29745 this.el.addClass("x-btn-focus");
29749 onBlur : function(e){
29750 this.el.removeClass("x-btn-focus");
29753 onMouseDown : function(e){
29754 if(!this.disabled && e.button == 0){
29755 this.el.addClass("x-btn-click");
29756 Roo.get(document).on('mouseup', this.onMouseUp, this);
29760 onMouseUp : function(e){
29762 this.el.removeClass("x-btn-click");
29763 Roo.get(document).un('mouseup', this.onMouseUp, this);
29767 onMenuShow : function(e){
29768 this.el.addClass("x-btn-menu-active");
29771 onMenuHide : function(e){
29772 this.el.removeClass("x-btn-menu-active");
29776 // Private utility class used by Button
29777 Roo.ButtonToggleMgr = function(){
29780 function toggleGroup(btn, state){
29782 var g = groups[btn.toggleGroup];
29783 for(var i = 0, l = g.length; i < l; i++){
29785 g[i].toggle(false);
29792 register : function(btn){
29793 if(!btn.toggleGroup){
29796 var g = groups[btn.toggleGroup];
29798 g = groups[btn.toggleGroup] = [];
29801 btn.on("toggle", toggleGroup);
29804 unregister : function(btn){
29805 if(!btn.toggleGroup){
29808 var g = groups[btn.toggleGroup];
29811 btn.un("toggle", toggleGroup);
29817 * Ext JS Library 1.1.1
29818 * Copyright(c) 2006-2007, Ext JS, LLC.
29820 * Originally Released Under LGPL - original licence link has changed is not relivant.
29823 * <script type="text/javascript">
29827 * @class Roo.SplitButton
29828 * @extends Roo.Button
29829 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29830 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29831 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29832 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29833 * @cfg {String} arrowTooltip The title attribute of the arrow
29835 * Create a new menu button
29836 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29837 * @param {Object} config The config object
29839 Roo.SplitButton = function(renderTo, config){
29840 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29842 * @event arrowclick
29843 * Fires when this button's arrow is clicked
29844 * @param {SplitButton} this
29845 * @param {EventObject} e The click event
29847 this.addEvents({"arrowclick":true});
29850 Roo.extend(Roo.SplitButton, Roo.Button, {
29851 render : function(renderTo){
29852 // this is one sweet looking template!
29853 var tpl = new Roo.Template(
29854 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29855 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29856 '<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>',
29857 "</tbody></table></td><td>",
29858 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29859 '<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>',
29860 "</tbody></table></td></tr></table>"
29862 var btn = tpl.append(renderTo, [this.text, this.type], true);
29863 var btnEl = btn.child("button");
29865 btn.addClass(this.cls);
29868 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29871 btnEl.addClass(this.iconCls);
29873 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29877 if(this.handleMouseEvents){
29878 btn.on("mouseover", this.onMouseOver, this);
29879 btn.on("mouseout", this.onMouseOut, this);
29880 btn.on("mousedown", this.onMouseDown, this);
29881 btn.on("mouseup", this.onMouseUp, this);
29883 btn.on(this.clickEvent, this.onClick, this);
29885 if(typeof this.tooltip == 'object'){
29886 Roo.QuickTips.tips(Roo.apply({
29890 btnEl.dom[this.tooltipType] = this.tooltip;
29893 if(this.arrowTooltip){
29894 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29903 this.el.addClass("x-btn-pressed");
29905 if(Roo.isIE && !Roo.isIE7){
29906 this.autoWidth.defer(1, this);
29911 this.menu.on("show", this.onMenuShow, this);
29912 this.menu.on("hide", this.onMenuHide, this);
29914 this.fireEvent('render', this);
29918 autoWidth : function(){
29920 var tbl = this.el.child("table:first");
29921 var tbl2 = this.el.child("table:last");
29922 this.el.setWidth("auto");
29923 tbl.setWidth("auto");
29924 if(Roo.isIE7 && Roo.isStrict){
29925 var ib = this.el.child('button:first');
29926 if(ib && ib.getWidth() > 20){
29928 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29933 this.el.beginMeasure();
29935 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29936 tbl.setWidth(this.minWidth-tbl2.getWidth());
29939 this.el.endMeasure();
29942 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29946 * Sets this button's click handler
29947 * @param {Function} handler The function to call when the button is clicked
29948 * @param {Object} scope (optional) Scope for the function passed above
29950 setHandler : function(handler, scope){
29951 this.handler = handler;
29952 this.scope = scope;
29956 * Sets this button's arrow click handler
29957 * @param {Function} handler The function to call when the arrow is clicked
29958 * @param {Object} scope (optional) Scope for the function passed above
29960 setArrowHandler : function(handler, scope){
29961 this.arrowHandler = handler;
29962 this.scope = scope;
29968 focus : function(){
29970 this.el.child("button:first").focus();
29975 onClick : function(e){
29976 e.preventDefault();
29977 if(!this.disabled){
29978 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29979 if(this.menu && !this.menu.isVisible()){
29980 this.menu.show(this.el, this.menuAlign);
29982 this.fireEvent("arrowclick", this, e);
29983 if(this.arrowHandler){
29984 this.arrowHandler.call(this.scope || this, this, e);
29987 this.fireEvent("click", this, e);
29989 this.handler.call(this.scope || this, this, e);
29995 onMouseDown : function(e){
29996 if(!this.disabled){
29997 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30001 onMouseUp : function(e){
30002 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30007 // backwards compat
30008 Roo.MenuButton = Roo.SplitButton;/*
30010 * Ext JS Library 1.1.1
30011 * Copyright(c) 2006-2007, Ext JS, LLC.
30013 * Originally Released Under LGPL - original licence link has changed is not relivant.
30016 * <script type="text/javascript">
30020 * @class Roo.Toolbar
30021 * Basic Toolbar class.
30023 * Creates a new Toolbar
30024 * @param {Object} container The config object
30026 Roo.Toolbar = function(container, buttons, config)
30028 /// old consturctor format still supported..
30029 if(container instanceof Array){ // omit the container for later rendering
30030 buttons = container;
30034 if (typeof(container) == 'object' && container.xtype) {
30035 config = container;
30036 container = config.container;
30037 buttons = config.buttons || []; // not really - use items!!
30040 if (config && config.items) {
30041 xitems = config.items;
30042 delete config.items;
30044 Roo.apply(this, config);
30045 this.buttons = buttons;
30048 this.render(container);
30050 this.xitems = xitems;
30051 Roo.each(xitems, function(b) {
30057 Roo.Toolbar.prototype = {
30059 * @cfg {Array} items
30060 * array of button configs or elements to add (will be converted to a MixedCollection)
30064 * @cfg {String/HTMLElement/Element} container
30065 * The id or element that will contain the toolbar
30068 render : function(ct){
30069 this.el = Roo.get(ct);
30071 this.el.addClass(this.cls);
30073 // using a table allows for vertical alignment
30074 // 100% width is needed by Safari...
30075 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30076 this.tr = this.el.child("tr", true);
30078 this.items = new Roo.util.MixedCollection(false, function(o){
30079 return o.id || ("item" + (++autoId));
30082 this.add.apply(this, this.buttons);
30083 delete this.buttons;
30088 * Adds element(s) to the toolbar -- this function takes a variable number of
30089 * arguments of mixed type and adds them to the toolbar.
30090 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30092 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30093 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30094 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30095 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30096 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30097 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30098 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30099 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30100 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30102 * @param {Mixed} arg2
30103 * @param {Mixed} etc.
30106 var a = arguments, l = a.length;
30107 for(var i = 0; i < l; i++){
30112 _add : function(el) {
30115 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30118 if (el.applyTo){ // some kind of form field
30119 return this.addField(el);
30121 if (el.render){ // some kind of Toolbar.Item
30122 return this.addItem(el);
30124 if (typeof el == "string"){ // string
30125 if(el == "separator" || el == "-"){
30126 return this.addSeparator();
30129 return this.addSpacer();
30132 return this.addFill();
30134 return this.addText(el);
30137 if(el.tagName){ // element
30138 return this.addElement(el);
30140 if(typeof el == "object"){ // must be button config?
30141 return this.addButton(el);
30143 // and now what?!?!
30149 * Add an Xtype element
30150 * @param {Object} xtype Xtype Object
30151 * @return {Object} created Object
30153 addxtype : function(e){
30154 return this.add(e);
30158 * Returns the Element for this toolbar.
30159 * @return {Roo.Element}
30161 getEl : function(){
30167 * @return {Roo.Toolbar.Item} The separator item
30169 addSeparator : function(){
30170 return this.addItem(new Roo.Toolbar.Separator());
30174 * Adds a spacer element
30175 * @return {Roo.Toolbar.Spacer} The spacer item
30177 addSpacer : function(){
30178 return this.addItem(new Roo.Toolbar.Spacer());
30182 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30183 * @return {Roo.Toolbar.Fill} The fill item
30185 addFill : function(){
30186 return this.addItem(new Roo.Toolbar.Fill());
30190 * Adds any standard HTML element to the toolbar
30191 * @param {String/HTMLElement/Element} el The element or id of the element to add
30192 * @return {Roo.Toolbar.Item} The element's item
30194 addElement : function(el){
30195 return this.addItem(new Roo.Toolbar.Item(el));
30198 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30199 * @type Roo.util.MixedCollection
30204 * Adds any Toolbar.Item or subclass
30205 * @param {Roo.Toolbar.Item} item
30206 * @return {Roo.Toolbar.Item} The item
30208 addItem : function(item){
30209 var td = this.nextBlock();
30211 this.items.add(item);
30216 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30217 * @param {Object/Array} config A button config or array of configs
30218 * @return {Roo.Toolbar.Button/Array}
30220 addButton : function(config){
30221 if(config instanceof Array){
30223 for(var i = 0, len = config.length; i < len; i++) {
30224 buttons.push(this.addButton(config[i]));
30229 if(!(config instanceof Roo.Toolbar.Button)){
30231 new Roo.Toolbar.SplitButton(config) :
30232 new Roo.Toolbar.Button(config);
30234 var td = this.nextBlock();
30241 * Adds text to the toolbar
30242 * @param {String} text The text to add
30243 * @return {Roo.Toolbar.Item} The element's item
30245 addText : function(text){
30246 return this.addItem(new Roo.Toolbar.TextItem(text));
30250 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30251 * @param {Number} index The index where the item is to be inserted
30252 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30253 * @return {Roo.Toolbar.Button/Item}
30255 insertButton : function(index, item){
30256 if(item instanceof Array){
30258 for(var i = 0, len = item.length; i < len; i++) {
30259 buttons.push(this.insertButton(index + i, item[i]));
30263 if (!(item instanceof Roo.Toolbar.Button)){
30264 item = new Roo.Toolbar.Button(item);
30266 var td = document.createElement("td");
30267 this.tr.insertBefore(td, this.tr.childNodes[index]);
30269 this.items.insert(index, item);
30274 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30275 * @param {Object} config
30276 * @return {Roo.Toolbar.Item} The element's item
30278 addDom : function(config, returnEl){
30279 var td = this.nextBlock();
30280 Roo.DomHelper.overwrite(td, config);
30281 var ti = new Roo.Toolbar.Item(td.firstChild);
30283 this.items.add(ti);
30288 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30289 * @type Roo.util.MixedCollection
30294 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30295 * Note: the field should not have been rendered yet. For a field that has already been
30296 * rendered, use {@link #addElement}.
30297 * @param {Roo.form.Field} field
30298 * @return {Roo.ToolbarItem}
30302 addField : function(field) {
30303 if (!this.fields) {
30305 this.fields = new Roo.util.MixedCollection(false, function(o){
30306 return o.id || ("item" + (++autoId));
30311 var td = this.nextBlock();
30313 var ti = new Roo.Toolbar.Item(td.firstChild);
30315 this.items.add(ti);
30316 this.fields.add(field);
30327 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30328 this.el.child('div').hide();
30336 this.el.child('div').show();
30340 nextBlock : function(){
30341 var td = document.createElement("td");
30342 this.tr.appendChild(td);
30347 destroy : function(){
30348 if(this.items){ // rendered?
30349 Roo.destroy.apply(Roo, this.items.items);
30351 if(this.fields){ // rendered?
30352 Roo.destroy.apply(Roo, this.fields.items);
30354 Roo.Element.uncache(this.el, this.tr);
30359 * @class Roo.Toolbar.Item
30360 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30362 * Creates a new Item
30363 * @param {HTMLElement} el
30365 Roo.Toolbar.Item = function(el){
30367 if (typeof (el.xtype) != 'undefined') {
30372 this.el = Roo.getDom(el);
30373 this.id = Roo.id(this.el);
30374 this.hidden = false;
30379 * Fires when the button is rendered
30380 * @param {Button} this
30384 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30386 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30387 //Roo.Toolbar.Item.prototype = {
30390 * Get this item's HTML Element
30391 * @return {HTMLElement}
30393 getEl : function(){
30398 render : function(td){
30401 td.appendChild(this.el);
30403 this.fireEvent('render', this);
30407 * Removes and destroys this item.
30409 destroy : function(){
30410 this.td.parentNode.removeChild(this.td);
30417 this.hidden = false;
30418 this.td.style.display = "";
30425 this.hidden = true;
30426 this.td.style.display = "none";
30430 * Convenience function for boolean show/hide.
30431 * @param {Boolean} visible true to show/false to hide
30433 setVisible: function(visible){
30442 * Try to focus this item.
30444 focus : function(){
30445 Roo.fly(this.el).focus();
30449 * Disables this item.
30451 disable : function(){
30452 Roo.fly(this.td).addClass("x-item-disabled");
30453 this.disabled = true;
30454 this.el.disabled = true;
30458 * Enables this item.
30460 enable : function(){
30461 Roo.fly(this.td).removeClass("x-item-disabled");
30462 this.disabled = false;
30463 this.el.disabled = false;
30469 * @class Roo.Toolbar.Separator
30470 * @extends Roo.Toolbar.Item
30471 * A simple toolbar separator class
30473 * Creates a new Separator
30475 Roo.Toolbar.Separator = function(cfg){
30477 var s = document.createElement("span");
30478 s.className = "ytb-sep";
30483 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30485 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30486 enable:Roo.emptyFn,
30487 disable:Roo.emptyFn,
30492 * @class Roo.Toolbar.Spacer
30493 * @extends Roo.Toolbar.Item
30494 * A simple element that adds extra horizontal space to a toolbar.
30496 * Creates a new Spacer
30498 Roo.Toolbar.Spacer = function(cfg){
30499 var s = document.createElement("div");
30500 s.className = "ytb-spacer";
30504 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30506 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30507 enable:Roo.emptyFn,
30508 disable:Roo.emptyFn,
30513 * @class Roo.Toolbar.Fill
30514 * @extends Roo.Toolbar.Spacer
30515 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30517 * Creates a new Spacer
30519 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30521 render : function(td){
30522 td.style.width = '100%';
30523 Roo.Toolbar.Fill.superclass.render.call(this, td);
30528 * @class Roo.Toolbar.TextItem
30529 * @extends Roo.Toolbar.Item
30530 * A simple class that renders text directly into a toolbar.
30532 * Creates a new TextItem
30533 * @cfg {string} text
30535 Roo.Toolbar.TextItem = function(cfg){
30536 var text = cfg || "";
30537 if (typeof(cfg) == 'object') {
30538 text = cfg.text || "";
30542 var s = document.createElement("span");
30543 s.className = "ytb-text";
30544 s.innerHTML = text;
30549 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30551 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30554 enable:Roo.emptyFn,
30555 disable:Roo.emptyFn,
30560 * @class Roo.Toolbar.Button
30561 * @extends Roo.Button
30562 * A button that renders into a toolbar.
30564 * Creates a new Button
30565 * @param {Object} config A standard {@link Roo.Button} config object
30567 Roo.Toolbar.Button = function(config){
30568 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30570 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30571 render : function(td){
30573 Roo.Toolbar.Button.superclass.render.call(this, td);
30577 * Removes and destroys this button
30579 destroy : function(){
30580 Roo.Toolbar.Button.superclass.destroy.call(this);
30581 this.td.parentNode.removeChild(this.td);
30585 * Shows this button
30588 this.hidden = false;
30589 this.td.style.display = "";
30593 * Hides this button
30596 this.hidden = true;
30597 this.td.style.display = "none";
30601 * Disables this item
30603 disable : function(){
30604 Roo.fly(this.td).addClass("x-item-disabled");
30605 this.disabled = true;
30609 * Enables this item
30611 enable : function(){
30612 Roo.fly(this.td).removeClass("x-item-disabled");
30613 this.disabled = false;
30616 // backwards compat
30617 Roo.ToolbarButton = Roo.Toolbar.Button;
30620 * @class Roo.Toolbar.SplitButton
30621 * @extends Roo.SplitButton
30622 * A menu button that renders into a toolbar.
30624 * Creates a new SplitButton
30625 * @param {Object} config A standard {@link Roo.SplitButton} config object
30627 Roo.Toolbar.SplitButton = function(config){
30628 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30630 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30631 render : function(td){
30633 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30637 * Removes and destroys this button
30639 destroy : function(){
30640 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30641 this.td.parentNode.removeChild(this.td);
30645 * Shows this button
30648 this.hidden = false;
30649 this.td.style.display = "";
30653 * Hides this button
30656 this.hidden = true;
30657 this.td.style.display = "none";
30661 // backwards compat
30662 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30664 * Ext JS Library 1.1.1
30665 * Copyright(c) 2006-2007, Ext JS, LLC.
30667 * Originally Released Under LGPL - original licence link has changed is not relivant.
30670 * <script type="text/javascript">
30674 * @class Roo.PagingToolbar
30675 * @extends Roo.Toolbar
30676 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30678 * Create a new PagingToolbar
30679 * @param {Object} config The config object
30681 Roo.PagingToolbar = function(el, ds, config)
30683 // old args format still supported... - xtype is prefered..
30684 if (typeof(el) == 'object' && el.xtype) {
30685 // created from xtype...
30687 ds = el.dataSource;
30688 el = config.container;
30691 if (config.items) {
30692 items = config.items;
30696 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30699 this.renderButtons(this.el);
30702 // supprot items array.
30704 Roo.each(items, function(e) {
30705 this.add(Roo.factory(e));
30710 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30712 * @cfg {Roo.data.Store} dataSource
30713 * The underlying data store providing the paged data
30716 * @cfg {String/HTMLElement/Element} container
30717 * container The id or element that will contain the toolbar
30720 * @cfg {Boolean} displayInfo
30721 * True to display the displayMsg (defaults to false)
30724 * @cfg {Number} pageSize
30725 * The number of records to display per page (defaults to 20)
30729 * @cfg {String} displayMsg
30730 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30732 displayMsg : 'Displaying {0} - {1} of {2}',
30734 * @cfg {String} emptyMsg
30735 * The message to display when no records are found (defaults to "No data to display")
30737 emptyMsg : 'No data to display',
30739 * Customizable piece of the default paging text (defaults to "Page")
30742 beforePageText : "Page",
30744 * Customizable piece of the default paging text (defaults to "of %0")
30747 afterPageText : "of {0}",
30749 * Customizable piece of the default paging text (defaults to "First Page")
30752 firstText : "First Page",
30754 * Customizable piece of the default paging text (defaults to "Previous Page")
30757 prevText : "Previous Page",
30759 * Customizable piece of the default paging text (defaults to "Next Page")
30762 nextText : "Next Page",
30764 * Customizable piece of the default paging text (defaults to "Last Page")
30767 lastText : "Last Page",
30769 * Customizable piece of the default paging text (defaults to "Refresh")
30772 refreshText : "Refresh",
30775 renderButtons : function(el){
30776 Roo.PagingToolbar.superclass.render.call(this, el);
30777 this.first = this.addButton({
30778 tooltip: this.firstText,
30779 cls: "x-btn-icon x-grid-page-first",
30781 handler: this.onClick.createDelegate(this, ["first"])
30783 this.prev = this.addButton({
30784 tooltip: this.prevText,
30785 cls: "x-btn-icon x-grid-page-prev",
30787 handler: this.onClick.createDelegate(this, ["prev"])
30789 //this.addSeparator();
30790 this.add(this.beforePageText);
30791 this.field = Roo.get(this.addDom({
30796 cls: "x-grid-page-number"
30798 this.field.on("keydown", this.onPagingKeydown, this);
30799 this.field.on("focus", function(){this.dom.select();});
30800 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30801 this.field.setHeight(18);
30802 //this.addSeparator();
30803 this.next = this.addButton({
30804 tooltip: this.nextText,
30805 cls: "x-btn-icon x-grid-page-next",
30807 handler: this.onClick.createDelegate(this, ["next"])
30809 this.last = this.addButton({
30810 tooltip: this.lastText,
30811 cls: "x-btn-icon x-grid-page-last",
30813 handler: this.onClick.createDelegate(this, ["last"])
30815 //this.addSeparator();
30816 this.loading = this.addButton({
30817 tooltip: this.refreshText,
30818 cls: "x-btn-icon x-grid-loading",
30819 handler: this.onClick.createDelegate(this, ["refresh"])
30822 if(this.displayInfo){
30823 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30828 updateInfo : function(){
30829 if(this.displayEl){
30830 var count = this.ds.getCount();
30831 var msg = count == 0 ?
30835 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30837 this.displayEl.update(msg);
30842 onLoad : function(ds, r, o){
30843 this.cursor = o.params ? o.params.start : 0;
30844 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30846 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30847 this.field.dom.value = ap;
30848 this.first.setDisabled(ap == 1);
30849 this.prev.setDisabled(ap == 1);
30850 this.next.setDisabled(ap == ps);
30851 this.last.setDisabled(ap == ps);
30852 this.loading.enable();
30857 getPageData : function(){
30858 var total = this.ds.getTotalCount();
30861 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30862 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30867 onLoadError : function(){
30868 this.loading.enable();
30872 onPagingKeydown : function(e){
30873 var k = e.getKey();
30874 var d = this.getPageData();
30876 var v = this.field.dom.value, pageNum;
30877 if(!v || isNaN(pageNum = parseInt(v, 10))){
30878 this.field.dom.value = d.activePage;
30881 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30882 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30885 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))
30887 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30888 this.field.dom.value = pageNum;
30889 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30892 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30894 var v = this.field.dom.value, pageNum;
30895 var increment = (e.shiftKey) ? 10 : 1;
30896 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30899 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30900 this.field.dom.value = d.activePage;
30903 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30905 this.field.dom.value = parseInt(v, 10) + increment;
30906 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30907 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30914 beforeLoad : function(){
30916 this.loading.disable();
30921 onClick : function(which){
30925 ds.load({params:{start: 0, limit: this.pageSize}});
30928 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30931 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30934 var total = ds.getTotalCount();
30935 var extra = total % this.pageSize;
30936 var lastStart = extra ? (total - extra) : total-this.pageSize;
30937 ds.load({params:{start: lastStart, limit: this.pageSize}});
30940 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30946 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30947 * @param {Roo.data.Store} store The data store to unbind
30949 unbind : function(ds){
30950 ds.un("beforeload", this.beforeLoad, this);
30951 ds.un("load", this.onLoad, this);
30952 ds.un("loadexception", this.onLoadError, this);
30953 ds.un("remove", this.updateInfo, this);
30954 ds.un("add", this.updateInfo, this);
30955 this.ds = undefined;
30959 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30960 * @param {Roo.data.Store} store The data store to bind
30962 bind : function(ds){
30963 ds.on("beforeload", this.beforeLoad, this);
30964 ds.on("load", this.onLoad, this);
30965 ds.on("loadexception", this.onLoadError, this);
30966 ds.on("remove", this.updateInfo, this);
30967 ds.on("add", this.updateInfo, this);
30972 * Ext JS Library 1.1.1
30973 * Copyright(c) 2006-2007, Ext JS, LLC.
30975 * Originally Released Under LGPL - original licence link has changed is not relivant.
30978 * <script type="text/javascript">
30982 * @class Roo.Resizable
30983 * @extends Roo.util.Observable
30984 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30985 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30986 * 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
30987 * the element will be wrapped for you automatically.</p>
30988 * <p>Here is the list of valid resize handles:</p>
30991 ------ -------------------
31000 'hd' horizontal drag
31003 * <p>Here's an example showing the creation of a typical Resizable:</p>
31005 var resizer = new Roo.Resizable("element-id", {
31013 resizer.on("resize", myHandler);
31015 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31016 * resizer.east.setDisplayed(false);</p>
31017 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31018 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31019 * resize operation's new size (defaults to [0, 0])
31020 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31021 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31022 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31023 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31024 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31025 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31026 * @cfg {Number} width The width of the element in pixels (defaults to null)
31027 * @cfg {Number} height The height of the element in pixels (defaults to null)
31028 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31029 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31030 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31031 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31032 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31033 * in favor of the handles config option (defaults to false)
31034 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31035 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31036 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31037 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31038 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31039 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31040 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31041 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31042 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31043 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31044 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31046 * Create a new resizable component
31047 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31048 * @param {Object} config configuration options
31050 Roo.Resizable = function(el, config)
31052 this.el = Roo.get(el);
31054 if(config && config.wrap){
31055 config.resizeChild = this.el;
31056 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31057 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31058 this.el.setStyle("overflow", "hidden");
31059 this.el.setPositioning(config.resizeChild.getPositioning());
31060 config.resizeChild.clearPositioning();
31061 if(!config.width || !config.height){
31062 var csize = config.resizeChild.getSize();
31063 this.el.setSize(csize.width, csize.height);
31065 if(config.pinned && !config.adjustments){
31066 config.adjustments = "auto";
31070 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31071 this.proxy.unselectable();
31072 this.proxy.enableDisplayMode('block');
31074 Roo.apply(this, config);
31077 this.disableTrackOver = true;
31078 this.el.addClass("x-resizable-pinned");
31080 // if the element isn't positioned, make it relative
31081 var position = this.el.getStyle("position");
31082 if(position != "absolute" && position != "fixed"){
31083 this.el.setStyle("position", "relative");
31085 if(!this.handles){ // no handles passed, must be legacy style
31086 this.handles = 's,e,se';
31087 if(this.multiDirectional){
31088 this.handles += ',n,w';
31091 if(this.handles == "all"){
31092 this.handles = "n s e w ne nw se sw";
31094 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31095 var ps = Roo.Resizable.positions;
31096 for(var i = 0, len = hs.length; i < len; i++){
31097 if(hs[i] && ps[hs[i]]){
31098 var pos = ps[hs[i]];
31099 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31103 this.corner = this.southeast;
31105 // updateBox = the box can move..
31106 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31107 this.updateBox = true;
31110 this.activeHandle = null;
31112 if(this.resizeChild){
31113 if(typeof this.resizeChild == "boolean"){
31114 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31116 this.resizeChild = Roo.get(this.resizeChild, true);
31120 if(this.adjustments == "auto"){
31121 var rc = this.resizeChild;
31122 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31123 if(rc && (hw || hn)){
31124 rc.position("relative");
31125 rc.setLeft(hw ? hw.el.getWidth() : 0);
31126 rc.setTop(hn ? hn.el.getHeight() : 0);
31128 this.adjustments = [
31129 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31130 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31134 if(this.draggable){
31135 this.dd = this.dynamic ?
31136 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31137 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31143 * @event beforeresize
31144 * Fired before resize is allowed. Set enabled to false to cancel resize.
31145 * @param {Roo.Resizable} this
31146 * @param {Roo.EventObject} e The mousedown event
31148 "beforeresize" : true,
31151 * Fired a resizing.
31152 * @param {Roo.Resizable} this
31153 * @param {Number} x The new x position
31154 * @param {Number} y The new y position
31155 * @param {Number} w The new w width
31156 * @param {Number} h The new h hight
31157 * @param {Roo.EventObject} e The mouseup event
31162 * Fired after a resize.
31163 * @param {Roo.Resizable} this
31164 * @param {Number} width The new width
31165 * @param {Number} height The new height
31166 * @param {Roo.EventObject} e The mouseup event
31171 if(this.width !== null && this.height !== null){
31172 this.resizeTo(this.width, this.height);
31174 this.updateChildSize();
31177 this.el.dom.style.zoom = 1;
31179 Roo.Resizable.superclass.constructor.call(this);
31182 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31183 resizeChild : false,
31184 adjustments : [0, 0],
31194 multiDirectional : false,
31195 disableTrackOver : false,
31196 easing : 'easeOutStrong',
31197 widthIncrement : 0,
31198 heightIncrement : 0,
31202 preserveRatio : false,
31203 transparent: false,
31209 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31211 constrainTo: undefined,
31213 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31215 resizeRegion: undefined,
31219 * Perform a manual resize
31220 * @param {Number} width
31221 * @param {Number} height
31223 resizeTo : function(width, height){
31224 this.el.setSize(width, height);
31225 this.updateChildSize();
31226 this.fireEvent("resize", this, width, height, null);
31230 startSizing : function(e, handle){
31231 this.fireEvent("beforeresize", this, e);
31232 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31235 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31236 this.overlay.unselectable();
31237 this.overlay.enableDisplayMode("block");
31238 this.overlay.on("mousemove", this.onMouseMove, this);
31239 this.overlay.on("mouseup", this.onMouseUp, this);
31241 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31243 this.resizing = true;
31244 this.startBox = this.el.getBox();
31245 this.startPoint = e.getXY();
31246 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31247 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31249 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31250 this.overlay.show();
31252 if(this.constrainTo) {
31253 var ct = Roo.get(this.constrainTo);
31254 this.resizeRegion = ct.getRegion().adjust(
31255 ct.getFrameWidth('t'),
31256 ct.getFrameWidth('l'),
31257 -ct.getFrameWidth('b'),
31258 -ct.getFrameWidth('r')
31262 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31264 this.proxy.setBox(this.startBox);
31266 this.proxy.setStyle('visibility', 'visible');
31272 onMouseDown : function(handle, e){
31275 this.activeHandle = handle;
31276 this.startSizing(e, handle);
31281 onMouseUp : function(e){
31282 var size = this.resizeElement();
31283 this.resizing = false;
31285 this.overlay.hide();
31287 this.fireEvent("resize", this, size.width, size.height, e);
31291 updateChildSize : function(){
31293 if(this.resizeChild){
31295 var child = this.resizeChild;
31296 var adj = this.adjustments;
31297 if(el.dom.offsetWidth){
31298 var b = el.getSize(true);
31299 child.setSize(b.width+adj[0], b.height+adj[1]);
31301 // Second call here for IE
31302 // The first call enables instant resizing and
31303 // the second call corrects scroll bars if they
31306 setTimeout(function(){
31307 if(el.dom.offsetWidth){
31308 var b = el.getSize(true);
31309 child.setSize(b.width+adj[0], b.height+adj[1]);
31317 snap : function(value, inc, min){
31318 if(!inc || !value) {
31321 var newValue = value;
31322 var m = value % inc;
31325 newValue = value + (inc-m);
31327 newValue = value - m;
31330 return Math.max(min, newValue);
31334 resizeElement : function(){
31335 var box = this.proxy.getBox();
31336 if(this.updateBox){
31337 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31339 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31341 this.updateChildSize();
31349 constrain : function(v, diff, m, mx){
31352 }else if(v - diff > mx){
31359 onMouseMove : function(e){
31362 try{// try catch so if something goes wrong the user doesn't get hung
31364 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31368 //var curXY = this.startPoint;
31369 var curSize = this.curSize || this.startBox;
31370 var x = this.startBox.x, y = this.startBox.y;
31371 var ox = x, oy = y;
31372 var w = curSize.width, h = curSize.height;
31373 var ow = w, oh = h;
31374 var mw = this.minWidth, mh = this.minHeight;
31375 var mxw = this.maxWidth, mxh = this.maxHeight;
31376 var wi = this.widthIncrement;
31377 var hi = this.heightIncrement;
31379 var eventXY = e.getXY();
31380 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31381 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31383 var pos = this.activeHandle.position;
31388 w = Math.min(Math.max(mw, w), mxw);
31393 h = Math.min(Math.max(mh, h), mxh);
31398 w = Math.min(Math.max(mw, w), mxw);
31399 h = Math.min(Math.max(mh, h), mxh);
31402 diffY = this.constrain(h, diffY, mh, mxh);
31409 var adiffX = Math.abs(diffX);
31410 var sub = (adiffX % wi); // how much
31411 if (sub > (wi/2)) { // far enough to snap
31412 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31414 // remove difference..
31415 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31419 x = Math.max(this.minX, x);
31422 diffX = this.constrain(w, diffX, mw, mxw);
31428 w = Math.min(Math.max(mw, w), mxw);
31429 diffY = this.constrain(h, diffY, mh, mxh);
31434 diffX = this.constrain(w, diffX, mw, mxw);
31435 diffY = this.constrain(h, diffY, mh, mxh);
31442 diffX = this.constrain(w, diffX, mw, mxw);
31444 h = Math.min(Math.max(mh, h), mxh);
31450 var sw = this.snap(w, wi, mw);
31451 var sh = this.snap(h, hi, mh);
31452 if(sw != w || sh != h){
31475 if(this.preserveRatio){
31480 h = Math.min(Math.max(mh, h), mxh);
31485 w = Math.min(Math.max(mw, w), mxw);
31490 w = Math.min(Math.max(mw, w), mxw);
31496 w = Math.min(Math.max(mw, w), mxw);
31502 h = Math.min(Math.max(mh, h), mxh);
31510 h = Math.min(Math.max(mh, h), mxh);
31520 h = Math.min(Math.max(mh, h), mxh);
31528 if (pos == 'hdrag') {
31531 this.proxy.setBounds(x, y, w, h);
31533 this.resizeElement();
31537 this.fireEvent("resizing", this, x, y, w, h, e);
31541 handleOver : function(){
31543 this.el.addClass("x-resizable-over");
31548 handleOut : function(){
31549 if(!this.resizing){
31550 this.el.removeClass("x-resizable-over");
31555 * Returns the element this component is bound to.
31556 * @return {Roo.Element}
31558 getEl : function(){
31563 * Returns the resizeChild element (or null).
31564 * @return {Roo.Element}
31566 getResizeChild : function(){
31567 return this.resizeChild;
31569 groupHandler : function()
31574 * Destroys this resizable. If the element was wrapped and
31575 * removeEl is not true then the element remains.
31576 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31578 destroy : function(removeEl){
31579 this.proxy.remove();
31581 this.overlay.removeAllListeners();
31582 this.overlay.remove();
31584 var ps = Roo.Resizable.positions;
31586 if(typeof ps[k] != "function" && this[ps[k]]){
31587 var h = this[ps[k]];
31588 h.el.removeAllListeners();
31593 this.el.update("");
31600 // hash to map config positions to true positions
31601 Roo.Resizable.positions = {
31602 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31607 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31609 // only initialize the template if resizable is used
31610 var tpl = Roo.DomHelper.createTemplate(
31611 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31614 Roo.Resizable.Handle.prototype.tpl = tpl;
31616 this.position = pos;
31618 // show north drag fro topdra
31619 var handlepos = pos == 'hdrag' ? 'north' : pos;
31621 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31622 if (pos == 'hdrag') {
31623 this.el.setStyle('cursor', 'pointer');
31625 this.el.unselectable();
31627 this.el.setOpacity(0);
31629 this.el.on("mousedown", this.onMouseDown, this);
31630 if(!disableTrackOver){
31631 this.el.on("mouseover", this.onMouseOver, this);
31632 this.el.on("mouseout", this.onMouseOut, this);
31637 Roo.Resizable.Handle.prototype = {
31638 afterResize : function(rz){
31643 onMouseDown : function(e){
31644 this.rz.onMouseDown(this, e);
31647 onMouseOver : function(e){
31648 this.rz.handleOver(this, e);
31651 onMouseOut : function(e){
31652 this.rz.handleOut(this, e);
31656 * Ext JS Library 1.1.1
31657 * Copyright(c) 2006-2007, Ext JS, LLC.
31659 * Originally Released Under LGPL - original licence link has changed is not relivant.
31662 * <script type="text/javascript">
31666 * @class Roo.Editor
31667 * @extends Roo.Component
31668 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31670 * Create a new Editor
31671 * @param {Roo.form.Field} field The Field object (or descendant)
31672 * @param {Object} config The config object
31674 Roo.Editor = function(field, config){
31675 Roo.Editor.superclass.constructor.call(this, config);
31676 this.field = field;
31679 * @event beforestartedit
31680 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31681 * false from the handler of this event.
31682 * @param {Editor} this
31683 * @param {Roo.Element} boundEl The underlying element bound to this editor
31684 * @param {Mixed} value The field value being set
31686 "beforestartedit" : true,
31689 * Fires when this editor is displayed
31690 * @param {Roo.Element} boundEl The underlying element bound to this editor
31691 * @param {Mixed} value The starting field value
31693 "startedit" : true,
31695 * @event beforecomplete
31696 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31697 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31698 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31699 * event will not fire since no edit actually occurred.
31700 * @param {Editor} this
31701 * @param {Mixed} value The current field value
31702 * @param {Mixed} startValue The original field value
31704 "beforecomplete" : true,
31707 * Fires after editing is complete and any changed value has been written to the underlying field.
31708 * @param {Editor} this
31709 * @param {Mixed} value The current field value
31710 * @param {Mixed} startValue The original field value
31714 * @event specialkey
31715 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31716 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31717 * @param {Roo.form.Field} this
31718 * @param {Roo.EventObject} e The event object
31720 "specialkey" : true
31724 Roo.extend(Roo.Editor, Roo.Component, {
31726 * @cfg {Boolean/String} autosize
31727 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31728 * or "height" to adopt the height only (defaults to false)
31731 * @cfg {Boolean} revertInvalid
31732 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31733 * validation fails (defaults to true)
31736 * @cfg {Boolean} ignoreNoChange
31737 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31738 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31739 * will never be ignored.
31742 * @cfg {Boolean} hideEl
31743 * False to keep the bound element visible while the editor is displayed (defaults to true)
31746 * @cfg {Mixed} value
31747 * The data value of the underlying field (defaults to "")
31751 * @cfg {String} alignment
31752 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31756 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31757 * for bottom-right shadow (defaults to "frame")
31761 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31765 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31767 completeOnEnter : false,
31769 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31771 cancelOnEsc : false,
31773 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31778 onRender : function(ct, position){
31779 this.el = new Roo.Layer({
31780 shadow: this.shadow,
31786 constrain: this.constrain
31788 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31789 if(this.field.msgTarget != 'title'){
31790 this.field.msgTarget = 'qtip';
31792 this.field.render(this.el);
31794 this.field.el.dom.setAttribute('autocomplete', 'off');
31796 this.field.on("specialkey", this.onSpecialKey, this);
31797 if(this.swallowKeys){
31798 this.field.el.swallowEvent(['keydown','keypress']);
31801 this.field.on("blur", this.onBlur, this);
31802 if(this.field.grow){
31803 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31807 onSpecialKey : function(field, e)
31809 //Roo.log('editor onSpecialKey');
31810 if(this.completeOnEnter && e.getKey() == e.ENTER){
31812 this.completeEdit();
31815 // do not fire special key otherwise it might hide close the editor...
31816 if(e.getKey() == e.ENTER){
31819 if(this.cancelOnEsc && e.getKey() == e.ESC){
31823 this.fireEvent('specialkey', field, e);
31828 * Starts the editing process and shows the editor.
31829 * @param {String/HTMLElement/Element} el The element to edit
31830 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31831 * to the innerHTML of el.
31833 startEdit : function(el, value){
31835 this.completeEdit();
31837 this.boundEl = Roo.get(el);
31838 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31839 if(!this.rendered){
31840 this.render(this.parentEl || document.body);
31842 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31845 this.startValue = v;
31846 this.field.setValue(v);
31848 var sz = this.boundEl.getSize();
31849 switch(this.autoSize){
31851 this.setSize(sz.width, "");
31854 this.setSize("", sz.height);
31857 this.setSize(sz.width, sz.height);
31860 this.el.alignTo(this.boundEl, this.alignment);
31861 this.editing = true;
31863 Roo.QuickTips.disable();
31869 * Sets the height and width of this editor.
31870 * @param {Number} width The new width
31871 * @param {Number} height The new height
31873 setSize : function(w, h){
31874 this.field.setSize(w, h);
31881 * Realigns the editor to the bound field based on the current alignment config value.
31883 realign : function(){
31884 this.el.alignTo(this.boundEl, this.alignment);
31888 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31889 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31891 completeEdit : function(remainVisible){
31895 var v = this.getValue();
31896 if(this.revertInvalid !== false && !this.field.isValid()){
31897 v = this.startValue;
31898 this.cancelEdit(true);
31900 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31901 this.editing = false;
31905 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31906 this.editing = false;
31907 if(this.updateEl && this.boundEl){
31908 this.boundEl.update(v);
31910 if(remainVisible !== true){
31913 this.fireEvent("complete", this, v, this.startValue);
31918 onShow : function(){
31920 if(this.hideEl !== false){
31921 this.boundEl.hide();
31924 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31925 this.fixIEFocus = true;
31926 this.deferredFocus.defer(50, this);
31928 this.field.focus();
31930 this.fireEvent("startedit", this.boundEl, this.startValue);
31933 deferredFocus : function(){
31935 this.field.focus();
31940 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31941 * reverted to the original starting value.
31942 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31943 * cancel (defaults to false)
31945 cancelEdit : function(remainVisible){
31947 this.setValue(this.startValue);
31948 if(remainVisible !== true){
31955 onBlur : function(){
31956 if(this.allowBlur !== true && this.editing){
31957 this.completeEdit();
31962 onHide : function(){
31964 this.completeEdit();
31968 if(this.field.collapse){
31969 this.field.collapse();
31972 if(this.hideEl !== false){
31973 this.boundEl.show();
31976 Roo.QuickTips.enable();
31981 * Sets the data value of the editor
31982 * @param {Mixed} value Any valid value supported by the underlying field
31984 setValue : function(v){
31985 this.field.setValue(v);
31989 * Gets the data value of the editor
31990 * @return {Mixed} The data value
31992 getValue : function(){
31993 return this.field.getValue();
31997 * Ext JS Library 1.1.1
31998 * Copyright(c) 2006-2007, Ext JS, LLC.
32000 * Originally Released Under LGPL - original licence link has changed is not relivant.
32003 * <script type="text/javascript">
32007 * @class Roo.BasicDialog
32008 * @extends Roo.util.Observable
32009 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32011 var dlg = new Roo.BasicDialog("my-dlg", {
32020 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32021 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32022 dlg.addButton('Cancel', dlg.hide, dlg);
32025 <b>A Dialog should always be a direct child of the body element.</b>
32026 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32027 * @cfg {String} title Default text to display in the title bar (defaults to null)
32028 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32029 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32030 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32031 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32032 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32033 * (defaults to null with no animation)
32034 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32035 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32036 * property for valid values (defaults to 'all')
32037 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32038 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32039 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32040 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32041 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32042 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32043 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32044 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32045 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32046 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32047 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32048 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32049 * draggable = true (defaults to false)
32050 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32051 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32052 * shadow (defaults to false)
32053 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32054 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32055 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32056 * @cfg {Array} buttons Array of buttons
32057 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32059 * Create a new BasicDialog.
32060 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32061 * @param {Object} config Configuration options
32063 Roo.BasicDialog = function(el, config){
32064 this.el = Roo.get(el);
32065 var dh = Roo.DomHelper;
32066 if(!this.el && config && config.autoCreate){
32067 if(typeof config.autoCreate == "object"){
32068 if(!config.autoCreate.id){
32069 config.autoCreate.id = el;
32071 this.el = dh.append(document.body,
32072 config.autoCreate, true);
32074 this.el = dh.append(document.body,
32075 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32079 el.setDisplayed(true);
32080 el.hide = this.hideAction;
32082 el.addClass("x-dlg");
32084 Roo.apply(this, config);
32086 this.proxy = el.createProxy("x-dlg-proxy");
32087 this.proxy.hide = this.hideAction;
32088 this.proxy.setOpacity(.5);
32092 el.setWidth(config.width);
32095 el.setHeight(config.height);
32097 this.size = el.getSize();
32098 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32099 this.xy = [config.x,config.y];
32101 this.xy = el.getCenterXY(true);
32103 /** The header element @type Roo.Element */
32104 this.header = el.child("> .x-dlg-hd");
32105 /** The body element @type Roo.Element */
32106 this.body = el.child("> .x-dlg-bd");
32107 /** The footer element @type Roo.Element */
32108 this.footer = el.child("> .x-dlg-ft");
32111 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32114 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32117 this.header.unselectable();
32119 this.header.update(this.title);
32121 // this element allows the dialog to be focused for keyboard event
32122 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32123 this.focusEl.swallowEvent("click", true);
32125 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32127 // wrap the body and footer for special rendering
32128 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32130 this.bwrap.dom.appendChild(this.footer.dom);
32133 this.bg = this.el.createChild({
32134 tag: "div", cls:"x-dlg-bg",
32135 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32137 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32140 if(this.autoScroll !== false && !this.autoTabs){
32141 this.body.setStyle("overflow", "auto");
32144 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32146 if(this.closable !== false){
32147 this.el.addClass("x-dlg-closable");
32148 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32149 this.close.on("click", this.closeClick, this);
32150 this.close.addClassOnOver("x-dlg-close-over");
32152 if(this.collapsible !== false){
32153 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32154 this.collapseBtn.on("click", this.collapseClick, this);
32155 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32156 this.header.on("dblclick", this.collapseClick, this);
32158 if(this.resizable !== false){
32159 this.el.addClass("x-dlg-resizable");
32160 this.resizer = new Roo.Resizable(el, {
32161 minWidth: this.minWidth || 80,
32162 minHeight:this.minHeight || 80,
32163 handles: this.resizeHandles || "all",
32166 this.resizer.on("beforeresize", this.beforeResize, this);
32167 this.resizer.on("resize", this.onResize, this);
32169 if(this.draggable !== false){
32170 el.addClass("x-dlg-draggable");
32171 if (!this.proxyDrag) {
32172 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32175 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32177 dd.setHandleElId(this.header.id);
32178 dd.endDrag = this.endMove.createDelegate(this);
32179 dd.startDrag = this.startMove.createDelegate(this);
32180 dd.onDrag = this.onDrag.createDelegate(this);
32185 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32186 this.mask.enableDisplayMode("block");
32188 this.el.addClass("x-dlg-modal");
32191 this.shadow = new Roo.Shadow({
32192 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32193 offset : this.shadowOffset
32196 this.shadowOffset = 0;
32198 if(Roo.useShims && this.shim !== false){
32199 this.shim = this.el.createShim();
32200 this.shim.hide = this.hideAction;
32208 if (this.buttons) {
32209 var bts= this.buttons;
32211 Roo.each(bts, function(b) {
32220 * Fires when a key is pressed
32221 * @param {Roo.BasicDialog} this
32222 * @param {Roo.EventObject} e
32227 * Fires when this dialog is moved by the user.
32228 * @param {Roo.BasicDialog} this
32229 * @param {Number} x The new page X
32230 * @param {Number} y The new page Y
32235 * Fires when this dialog is resized by the user.
32236 * @param {Roo.BasicDialog} this
32237 * @param {Number} width The new width
32238 * @param {Number} height The new height
32242 * @event beforehide
32243 * Fires before this dialog is hidden.
32244 * @param {Roo.BasicDialog} this
32246 "beforehide" : true,
32249 * Fires when this dialog is hidden.
32250 * @param {Roo.BasicDialog} this
32254 * @event beforeshow
32255 * Fires before this dialog is shown.
32256 * @param {Roo.BasicDialog} this
32258 "beforeshow" : true,
32261 * Fires when this dialog is shown.
32262 * @param {Roo.BasicDialog} this
32266 el.on("keydown", this.onKeyDown, this);
32267 el.on("mousedown", this.toFront, this);
32268 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32270 Roo.DialogManager.register(this);
32271 Roo.BasicDialog.superclass.constructor.call(this);
32274 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32275 shadowOffset: Roo.isIE ? 6 : 5,
32278 minButtonWidth: 75,
32279 defaultButton: null,
32280 buttonAlign: "right",
32285 * Sets the dialog title text
32286 * @param {String} text The title text to display
32287 * @return {Roo.BasicDialog} this
32289 setTitle : function(text){
32290 this.header.update(text);
32295 closeClick : function(){
32300 collapseClick : function(){
32301 this[this.collapsed ? "expand" : "collapse"]();
32305 * Collapses the dialog to its minimized state (only the title bar is visible).
32306 * Equivalent to the user clicking the collapse dialog button.
32308 collapse : function(){
32309 if(!this.collapsed){
32310 this.collapsed = true;
32311 this.el.addClass("x-dlg-collapsed");
32312 this.restoreHeight = this.el.getHeight();
32313 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32318 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32319 * clicking the expand dialog button.
32321 expand : function(){
32322 if(this.collapsed){
32323 this.collapsed = false;
32324 this.el.removeClass("x-dlg-collapsed");
32325 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32330 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32331 * @return {Roo.TabPanel} The tabs component
32333 initTabs : function(){
32334 var tabs = this.getTabs();
32335 while(tabs.getTab(0)){
32338 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32340 tabs.addTab(Roo.id(dom), dom.title);
32348 beforeResize : function(){
32349 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32353 onResize : function(){
32354 this.refreshSize();
32355 this.syncBodyHeight();
32356 this.adjustAssets();
32358 this.fireEvent("resize", this, this.size.width, this.size.height);
32362 onKeyDown : function(e){
32363 if(this.isVisible()){
32364 this.fireEvent("keydown", this, e);
32369 * Resizes the dialog.
32370 * @param {Number} width
32371 * @param {Number} height
32372 * @return {Roo.BasicDialog} this
32374 resizeTo : function(width, height){
32375 this.el.setSize(width, height);
32376 this.size = {width: width, height: height};
32377 this.syncBodyHeight();
32378 if(this.fixedcenter){
32381 if(this.isVisible()){
32382 this.constrainXY();
32383 this.adjustAssets();
32385 this.fireEvent("resize", this, width, height);
32391 * Resizes the dialog to fit the specified content size.
32392 * @param {Number} width
32393 * @param {Number} height
32394 * @return {Roo.BasicDialog} this
32396 setContentSize : function(w, h){
32397 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32398 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32399 //if(!this.el.isBorderBox()){
32400 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32401 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32404 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32405 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32407 this.resizeTo(w, h);
32412 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32413 * executed in response to a particular key being pressed while the dialog is active.
32414 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32415 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32416 * @param {Function} fn The function to call
32417 * @param {Object} scope (optional) The scope of the function
32418 * @return {Roo.BasicDialog} this
32420 addKeyListener : function(key, fn, scope){
32421 var keyCode, shift, ctrl, alt;
32422 if(typeof key == "object" && !(key instanceof Array)){
32423 keyCode = key["key"];
32424 shift = key["shift"];
32425 ctrl = key["ctrl"];
32430 var handler = function(dlg, e){
32431 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32432 var k = e.getKey();
32433 if(keyCode instanceof Array){
32434 for(var i = 0, len = keyCode.length; i < len; i++){
32435 if(keyCode[i] == k){
32436 fn.call(scope || window, dlg, k, e);
32442 fn.call(scope || window, dlg, k, e);
32447 this.on("keydown", handler);
32452 * Returns the TabPanel component (creates it if it doesn't exist).
32453 * Note: If you wish to simply check for the existence of tabs without creating them,
32454 * check for a null 'tabs' property.
32455 * @return {Roo.TabPanel} The tabs component
32457 getTabs : function(){
32459 this.el.addClass("x-dlg-auto-tabs");
32460 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32461 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32467 * Adds a button to the footer section of the dialog.
32468 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32469 * object or a valid Roo.DomHelper element config
32470 * @param {Function} handler The function called when the button is clicked
32471 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32472 * @return {Roo.Button} The new button
32474 addButton : function(config, handler, scope){
32475 var dh = Roo.DomHelper;
32477 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32479 if(!this.btnContainer){
32480 var tb = this.footer.createChild({
32482 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32483 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32485 this.btnContainer = tb.firstChild.firstChild.firstChild;
32490 minWidth: this.minButtonWidth,
32493 if(typeof config == "string"){
32494 bconfig.text = config;
32497 bconfig.dhconfig = config;
32499 Roo.apply(bconfig, config);
32503 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32504 bconfig.position = Math.max(0, bconfig.position);
32505 fc = this.btnContainer.childNodes[bconfig.position];
32508 var btn = new Roo.Button(
32510 this.btnContainer.insertBefore(document.createElement("td"),fc)
32511 : this.btnContainer.appendChild(document.createElement("td")),
32512 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32515 this.syncBodyHeight();
32518 * Array of all the buttons that have been added to this dialog via addButton
32523 this.buttons.push(btn);
32528 * Sets the default button to be focused when the dialog is displayed.
32529 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32530 * @return {Roo.BasicDialog} this
32532 setDefaultButton : function(btn){
32533 this.defaultButton = btn;
32538 getHeaderFooterHeight : function(safe){
32541 height += this.header.getHeight();
32544 var fm = this.footer.getMargins();
32545 height += (this.footer.getHeight()+fm.top+fm.bottom);
32547 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32548 height += this.centerBg.getPadding("tb");
32553 syncBodyHeight : function()
32555 var bd = this.body, // the text
32556 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32558 var height = this.size.height - this.getHeaderFooterHeight(false);
32559 bd.setHeight(height-bd.getMargins("tb"));
32560 var hh = this.header.getHeight();
32561 var h = this.size.height-hh;
32564 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32565 bw.setHeight(h-cb.getPadding("tb"));
32567 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32568 bd.setWidth(bw.getWidth(true));
32570 this.tabs.syncHeight();
32572 this.tabs.el.repaint();
32578 * Restores the previous state of the dialog if Roo.state is configured.
32579 * @return {Roo.BasicDialog} this
32581 restoreState : function(){
32582 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32583 if(box && box.width){
32584 this.xy = [box.x, box.y];
32585 this.resizeTo(box.width, box.height);
32591 beforeShow : function(){
32593 if(this.fixedcenter){
32594 this.xy = this.el.getCenterXY(true);
32597 Roo.get(document.body).addClass("x-body-masked");
32598 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32601 this.constrainXY();
32605 animShow : function(){
32606 var b = Roo.get(this.animateTarget).getBox();
32607 this.proxy.setSize(b.width, b.height);
32608 this.proxy.setLocation(b.x, b.y);
32610 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32611 true, .35, this.showEl.createDelegate(this));
32615 * Shows the dialog.
32616 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32617 * @return {Roo.BasicDialog} this
32619 show : function(animateTarget){
32620 if (this.fireEvent("beforeshow", this) === false){
32623 if(this.syncHeightBeforeShow){
32624 this.syncBodyHeight();
32625 }else if(this.firstShow){
32626 this.firstShow = false;
32627 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32629 this.animateTarget = animateTarget || this.animateTarget;
32630 if(!this.el.isVisible()){
32632 if(this.animateTarget && Roo.get(this.animateTarget)){
32642 showEl : function(){
32644 this.el.setXY(this.xy);
32646 this.adjustAssets(true);
32649 // IE peekaboo bug - fix found by Dave Fenwick
32653 this.fireEvent("show", this);
32657 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32658 * dialog itself will receive focus.
32660 focus : function(){
32661 if(this.defaultButton){
32662 this.defaultButton.focus();
32664 this.focusEl.focus();
32669 constrainXY : function(){
32670 if(this.constraintoviewport !== false){
32671 if(!this.viewSize){
32672 if(this.container){
32673 var s = this.container.getSize();
32674 this.viewSize = [s.width, s.height];
32676 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32679 var s = Roo.get(this.container||document).getScroll();
32681 var x = this.xy[0], y = this.xy[1];
32682 var w = this.size.width, h = this.size.height;
32683 var vw = this.viewSize[0], vh = this.viewSize[1];
32684 // only move it if it needs it
32686 // first validate right/bottom
32687 if(x + w > vw+s.left){
32691 if(y + h > vh+s.top){
32695 // then make sure top/left isn't negative
32707 if(this.isVisible()){
32708 this.el.setLocation(x, y);
32709 this.adjustAssets();
32716 onDrag : function(){
32717 if(!this.proxyDrag){
32718 this.xy = this.el.getXY();
32719 this.adjustAssets();
32724 adjustAssets : function(doShow){
32725 var x = this.xy[0], y = this.xy[1];
32726 var w = this.size.width, h = this.size.height;
32727 if(doShow === true){
32729 this.shadow.show(this.el);
32735 if(this.shadow && this.shadow.isVisible()){
32736 this.shadow.show(this.el);
32738 if(this.shim && this.shim.isVisible()){
32739 this.shim.setBounds(x, y, w, h);
32744 adjustViewport : function(w, h){
32746 w = Roo.lib.Dom.getViewWidth();
32747 h = Roo.lib.Dom.getViewHeight();
32750 this.viewSize = [w, h];
32751 if(this.modal && this.mask.isVisible()){
32752 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32753 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32755 if(this.isVisible()){
32756 this.constrainXY();
32761 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32762 * shadow, proxy, mask, etc.) Also removes all event listeners.
32763 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32765 destroy : function(removeEl){
32766 if(this.isVisible()){
32767 this.animateTarget = null;
32770 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32772 this.tabs.destroy(removeEl);
32785 for(var i = 0, len = this.buttons.length; i < len; i++){
32786 this.buttons[i].destroy();
32789 this.el.removeAllListeners();
32790 if(removeEl === true){
32791 this.el.update("");
32794 Roo.DialogManager.unregister(this);
32798 startMove : function(){
32799 if(this.proxyDrag){
32802 if(this.constraintoviewport !== false){
32803 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32808 endMove : function(){
32809 if(!this.proxyDrag){
32810 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32812 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32815 this.refreshSize();
32816 this.adjustAssets();
32818 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32822 * Brings this dialog to the front of any other visible dialogs
32823 * @return {Roo.BasicDialog} this
32825 toFront : function(){
32826 Roo.DialogManager.bringToFront(this);
32831 * Sends this dialog to the back (under) of any other visible dialogs
32832 * @return {Roo.BasicDialog} this
32834 toBack : function(){
32835 Roo.DialogManager.sendToBack(this);
32840 * Centers this dialog in the viewport
32841 * @return {Roo.BasicDialog} this
32843 center : function(){
32844 var xy = this.el.getCenterXY(true);
32845 this.moveTo(xy[0], xy[1]);
32850 * Moves the dialog's top-left corner to the specified point
32851 * @param {Number} x
32852 * @param {Number} y
32853 * @return {Roo.BasicDialog} this
32855 moveTo : function(x, y){
32857 if(this.isVisible()){
32858 this.el.setXY(this.xy);
32859 this.adjustAssets();
32865 * Aligns the dialog to the specified element
32866 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32867 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32868 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32869 * @return {Roo.BasicDialog} this
32871 alignTo : function(element, position, offsets){
32872 this.xy = this.el.getAlignToXY(element, position, offsets);
32873 if(this.isVisible()){
32874 this.el.setXY(this.xy);
32875 this.adjustAssets();
32881 * Anchors an element to another element and realigns it when the window is resized.
32882 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32883 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32884 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32885 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32886 * is a number, it is used as the buffer delay (defaults to 50ms).
32887 * @return {Roo.BasicDialog} this
32889 anchorTo : function(el, alignment, offsets, monitorScroll){
32890 var action = function(){
32891 this.alignTo(el, alignment, offsets);
32893 Roo.EventManager.onWindowResize(action, this);
32894 var tm = typeof monitorScroll;
32895 if(tm != 'undefined'){
32896 Roo.EventManager.on(window, 'scroll', action, this,
32897 {buffer: tm == 'number' ? monitorScroll : 50});
32904 * Returns true if the dialog is visible
32905 * @return {Boolean}
32907 isVisible : function(){
32908 return this.el.isVisible();
32912 animHide : function(callback){
32913 var b = Roo.get(this.animateTarget).getBox();
32915 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32917 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32918 this.hideEl.createDelegate(this, [callback]));
32922 * Hides the dialog.
32923 * @param {Function} callback (optional) Function to call when the dialog is hidden
32924 * @return {Roo.BasicDialog} this
32926 hide : function(callback){
32927 if (this.fireEvent("beforehide", this) === false){
32931 this.shadow.hide();
32936 // sometimes animateTarget seems to get set.. causing problems...
32937 // this just double checks..
32938 if(this.animateTarget && Roo.get(this.animateTarget)) {
32939 this.animHide(callback);
32942 this.hideEl(callback);
32948 hideEl : function(callback){
32952 Roo.get(document.body).removeClass("x-body-masked");
32954 this.fireEvent("hide", this);
32955 if(typeof callback == "function"){
32961 hideAction : function(){
32962 this.setLeft("-10000px");
32963 this.setTop("-10000px");
32964 this.setStyle("visibility", "hidden");
32968 refreshSize : function(){
32969 this.size = this.el.getSize();
32970 this.xy = this.el.getXY();
32971 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32975 // z-index is managed by the DialogManager and may be overwritten at any time
32976 setZIndex : function(index){
32978 this.mask.setStyle("z-index", index);
32981 this.shim.setStyle("z-index", ++index);
32984 this.shadow.setZIndex(++index);
32986 this.el.setStyle("z-index", ++index);
32988 this.proxy.setStyle("z-index", ++index);
32991 this.resizer.proxy.setStyle("z-index", ++index);
32994 this.lastZIndex = index;
32998 * Returns the element for this dialog
32999 * @return {Roo.Element} The underlying dialog Element
33001 getEl : function(){
33007 * @class Roo.DialogManager
33008 * Provides global access to BasicDialogs that have been created and
33009 * support for z-indexing (layering) multiple open dialogs.
33011 Roo.DialogManager = function(){
33013 var accessList = [];
33017 var sortDialogs = function(d1, d2){
33018 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33022 var orderDialogs = function(){
33023 accessList.sort(sortDialogs);
33024 var seed = Roo.DialogManager.zseed;
33025 for(var i = 0, len = accessList.length; i < len; i++){
33026 var dlg = accessList[i];
33028 dlg.setZIndex(seed + (i*10));
33035 * The starting z-index for BasicDialogs (defaults to 9000)
33036 * @type Number The z-index value
33041 register : function(dlg){
33042 list[dlg.id] = dlg;
33043 accessList.push(dlg);
33047 unregister : function(dlg){
33048 delete list[dlg.id];
33051 if(!accessList.indexOf){
33052 for( i = 0, len = accessList.length; i < len; i++){
33053 if(accessList[i] == dlg){
33054 accessList.splice(i, 1);
33059 i = accessList.indexOf(dlg);
33061 accessList.splice(i, 1);
33067 * Gets a registered dialog by id
33068 * @param {String/Object} id The id of the dialog or a dialog
33069 * @return {Roo.BasicDialog} this
33071 get : function(id){
33072 return typeof id == "object" ? id : list[id];
33076 * Brings the specified dialog to the front
33077 * @param {String/Object} dlg The id of the dialog or a dialog
33078 * @return {Roo.BasicDialog} this
33080 bringToFront : function(dlg){
33081 dlg = this.get(dlg);
33084 dlg._lastAccess = new Date().getTime();
33091 * Sends the specified dialog to the back
33092 * @param {String/Object} dlg The id of the dialog or a dialog
33093 * @return {Roo.BasicDialog} this
33095 sendToBack : function(dlg){
33096 dlg = this.get(dlg);
33097 dlg._lastAccess = -(new Date().getTime());
33103 * Hides all dialogs
33105 hideAll : function(){
33106 for(var id in list){
33107 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33116 * @class Roo.LayoutDialog
33117 * @extends Roo.BasicDialog
33118 * Dialog which provides adjustments for working with a layout in a Dialog.
33119 * Add your necessary layout config options to the dialog's config.<br>
33120 * Example usage (including a nested layout):
33123 dialog = new Roo.LayoutDialog("download-dlg", {
33132 // layout config merges with the dialog config
33134 tabPosition: "top",
33135 alwaysShowTabs: true
33138 dialog.addKeyListener(27, dialog.hide, dialog);
33139 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33140 dialog.addButton("Build It!", this.getDownload, this);
33142 // we can even add nested layouts
33143 var innerLayout = new Roo.BorderLayout("dl-inner", {
33153 innerLayout.beginUpdate();
33154 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33155 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33156 innerLayout.endUpdate(true);
33158 var layout = dialog.getLayout();
33159 layout.beginUpdate();
33160 layout.add("center", new Roo.ContentPanel("standard-panel",
33161 {title: "Download the Source", fitToFrame:true}));
33162 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33163 {title: "Build your own roo.js"}));
33164 layout.getRegion("center").showPanel(sp);
33165 layout.endUpdate();
33169 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33170 * @param {Object} config configuration options
33172 Roo.LayoutDialog = function(el, cfg){
33175 if (typeof(cfg) == 'undefined') {
33176 config = Roo.apply({}, el);
33177 // not sure why we use documentElement here.. - it should always be body.
33178 // IE7 borks horribly if we use documentElement.
33179 // webkit also does not like documentElement - it creates a body element...
33180 el = Roo.get( document.body || document.documentElement ).createChild();
33181 //config.autoCreate = true;
33185 config.autoTabs = false;
33186 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33187 this.body.setStyle({overflow:"hidden", position:"relative"});
33188 this.layout = new Roo.BorderLayout(this.body.dom, config);
33189 this.layout.monitorWindowResize = false;
33190 this.el.addClass("x-dlg-auto-layout");
33191 // fix case when center region overwrites center function
33192 this.center = Roo.BasicDialog.prototype.center;
33193 this.on("show", this.layout.layout, this.layout, true);
33194 if (config.items) {
33195 var xitems = config.items;
33196 delete config.items;
33197 Roo.each(xitems, this.addxtype, this);
33202 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33204 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33207 endUpdate : function(){
33208 this.layout.endUpdate();
33212 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33215 beginUpdate : function(){
33216 this.layout.beginUpdate();
33220 * Get the BorderLayout for this dialog
33221 * @return {Roo.BorderLayout}
33223 getLayout : function(){
33224 return this.layout;
33227 showEl : function(){
33228 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33230 this.layout.layout();
33235 // Use the syncHeightBeforeShow config option to control this automatically
33236 syncBodyHeight : function(){
33237 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33238 if(this.layout){this.layout.layout();}
33242 * Add an xtype element (actually adds to the layout.)
33243 * @return {Object} xdata xtype object data.
33246 addxtype : function(c) {
33247 return this.layout.addxtype(c);
33251 * Ext JS Library 1.1.1
33252 * Copyright(c) 2006-2007, Ext JS, LLC.
33254 * Originally Released Under LGPL - original licence link has changed is not relivant.
33257 * <script type="text/javascript">
33261 * @class Roo.MessageBox
33262 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33266 Roo.Msg.alert('Status', 'Changes saved successfully.');
33268 // Prompt for user data:
33269 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33271 // process text value...
33275 // Show a dialog using config options:
33277 title:'Save Changes?',
33278 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33279 buttons: Roo.Msg.YESNOCANCEL,
33286 Roo.MessageBox = function(){
33287 var dlg, opt, mask, waitTimer;
33288 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33289 var buttons, activeTextEl, bwidth;
33292 var handleButton = function(button){
33294 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33298 var handleHide = function(){
33299 if(opt && opt.cls){
33300 dlg.el.removeClass(opt.cls);
33303 Roo.TaskMgr.stop(waitTimer);
33309 var updateButtons = function(b){
33312 buttons["ok"].hide();
33313 buttons["cancel"].hide();
33314 buttons["yes"].hide();
33315 buttons["no"].hide();
33316 dlg.footer.dom.style.display = 'none';
33319 dlg.footer.dom.style.display = '';
33320 for(var k in buttons){
33321 if(typeof buttons[k] != "function"){
33324 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33325 width += buttons[k].el.getWidth()+15;
33335 var handleEsc = function(d, k, e){
33336 if(opt && opt.closable !== false){
33346 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33347 * @return {Roo.BasicDialog} The BasicDialog element
33349 getDialog : function(){
33351 dlg = new Roo.BasicDialog("x-msg-box", {
33356 constraintoviewport:false,
33358 collapsible : false,
33361 width:400, height:100,
33362 buttonAlign:"center",
33363 closeClick : function(){
33364 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33365 handleButton("no");
33367 handleButton("cancel");
33371 dlg.on("hide", handleHide);
33373 dlg.addKeyListener(27, handleEsc);
33375 var bt = this.buttonText;
33376 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33377 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33378 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33379 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33380 bodyEl = dlg.body.createChild({
33382 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>'
33384 msgEl = bodyEl.dom.firstChild;
33385 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33386 textboxEl.enableDisplayMode();
33387 textboxEl.addKeyListener([10,13], function(){
33388 if(dlg.isVisible() && opt && opt.buttons){
33389 if(opt.buttons.ok){
33390 handleButton("ok");
33391 }else if(opt.buttons.yes){
33392 handleButton("yes");
33396 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33397 textareaEl.enableDisplayMode();
33398 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33399 progressEl.enableDisplayMode();
33400 var pf = progressEl.dom.firstChild;
33402 pp = Roo.get(pf.firstChild);
33403 pp.setHeight(pf.offsetHeight);
33411 * Updates the message box body text
33412 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33413 * the XHTML-compliant non-breaking space character '&#160;')
33414 * @return {Roo.MessageBox} This message box
33416 updateText : function(text){
33417 if(!dlg.isVisible() && !opt.width){
33418 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33420 msgEl.innerHTML = text || ' ';
33422 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33423 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33425 Math.min(opt.width || cw , this.maxWidth),
33426 Math.max(opt.minWidth || this.minWidth, bwidth)
33429 activeTextEl.setWidth(w);
33431 if(dlg.isVisible()){
33432 dlg.fixedcenter = false;
33434 // to big, make it scroll. = But as usual stupid IE does not support
33437 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33438 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33439 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33441 bodyEl.dom.style.height = '';
33442 bodyEl.dom.style.overflowY = '';
33445 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33447 bodyEl.dom.style.overflowX = '';
33450 dlg.setContentSize(w, bodyEl.getHeight());
33451 if(dlg.isVisible()){
33452 dlg.fixedcenter = true;
33458 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33459 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33460 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33461 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33462 * @return {Roo.MessageBox} This message box
33464 updateProgress : function(value, text){
33466 this.updateText(text);
33468 if (pp) { // weird bug on my firefox - for some reason this is not defined
33469 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33475 * Returns true if the message box is currently displayed
33476 * @return {Boolean} True if the message box is visible, else false
33478 isVisible : function(){
33479 return dlg && dlg.isVisible();
33483 * Hides the message box if it is displayed
33486 if(this.isVisible()){
33492 * Displays a new message box, or reinitializes an existing message box, based on the config options
33493 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33494 * The following config object properties are supported:
33496 Property Type Description
33497 ---------- --------------- ------------------------------------------------------------------------------------
33498 animEl String/Element An id or Element from which the message box should animate as it opens and
33499 closes (defaults to undefined)
33500 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33501 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33502 closable Boolean False to hide the top-right close button (defaults to true). Note that
33503 progress and wait dialogs will ignore this property and always hide the
33504 close button as they can only be closed programmatically.
33505 cls String A custom CSS class to apply to the message box element
33506 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33507 displayed (defaults to 75)
33508 fn Function A callback function to execute after closing the dialog. The arguments to the
33509 function will be btn (the name of the button that was clicked, if applicable,
33510 e.g. "ok"), and text (the value of the active text field, if applicable).
33511 Progress and wait dialogs will ignore this option since they do not respond to
33512 user actions and can only be closed programmatically, so any required function
33513 should be called by the same code after it closes the dialog.
33514 icon String A CSS class that provides a background image to be used as an icon for
33515 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33516 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33517 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33518 modal Boolean False to allow user interaction with the page while the message box is
33519 displayed (defaults to true)
33520 msg String A string that will replace the existing message box body text (defaults
33521 to the XHTML-compliant non-breaking space character ' ')
33522 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33523 progress Boolean True to display a progress bar (defaults to false)
33524 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33525 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33526 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33527 title String The title text
33528 value String The string value to set into the active textbox element if displayed
33529 wait Boolean True to display a progress bar (defaults to false)
33530 width Number The width of the dialog in pixels
33537 msg: 'Please enter your address:',
33539 buttons: Roo.MessageBox.OKCANCEL,
33542 animEl: 'addAddressBtn'
33545 * @param {Object} config Configuration options
33546 * @return {Roo.MessageBox} This message box
33548 show : function(options)
33551 // this causes nightmares if you show one dialog after another
33552 // especially on callbacks..
33554 if(this.isVisible()){
33557 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33558 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33559 Roo.log("New Dialog Message:" + options.msg )
33560 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33561 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33564 var d = this.getDialog();
33566 d.setTitle(opt.title || " ");
33567 d.close.setDisplayed(opt.closable !== false);
33568 activeTextEl = textboxEl;
33569 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33574 textareaEl.setHeight(typeof opt.multiline == "number" ?
33575 opt.multiline : this.defaultTextHeight);
33576 activeTextEl = textareaEl;
33585 progressEl.setDisplayed(opt.progress === true);
33586 this.updateProgress(0);
33587 activeTextEl.dom.value = opt.value || "";
33589 dlg.setDefaultButton(activeTextEl);
33591 var bs = opt.buttons;
33594 db = buttons["ok"];
33595 }else if(bs && bs.yes){
33596 db = buttons["yes"];
33598 dlg.setDefaultButton(db);
33600 bwidth = updateButtons(opt.buttons);
33601 this.updateText(opt.msg);
33603 d.el.addClass(opt.cls);
33605 d.proxyDrag = opt.proxyDrag === true;
33606 d.modal = opt.modal !== false;
33607 d.mask = opt.modal !== false ? mask : false;
33608 if(!d.isVisible()){
33609 // force it to the end of the z-index stack so it gets a cursor in FF
33610 document.body.appendChild(dlg.el.dom);
33611 d.animateTarget = null;
33612 d.show(options.animEl);
33618 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33619 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33620 * and closing the message box when the process is complete.
33621 * @param {String} title The title bar text
33622 * @param {String} msg The message box body text
33623 * @return {Roo.MessageBox} This message box
33625 progress : function(title, msg){
33632 minWidth: this.minProgressWidth,
33639 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33640 * If a callback function is passed it will be called after the user clicks the button, and the
33641 * id of the button that was clicked will be passed as the only parameter to the callback
33642 * (could also be the top-right close button).
33643 * @param {String} title The title bar text
33644 * @param {String} msg The message box body text
33645 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33646 * @param {Object} scope (optional) The scope of the callback function
33647 * @return {Roo.MessageBox} This message box
33649 alert : function(title, msg, fn, scope){
33662 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33663 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33664 * You are responsible for closing the message box when the process is complete.
33665 * @param {String} msg The message box body text
33666 * @param {String} title (optional) The title bar text
33667 * @return {Roo.MessageBox} This message box
33669 wait : function(msg, title){
33680 waitTimer = Roo.TaskMgr.start({
33682 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33690 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33691 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33692 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33693 * @param {String} title The title bar text
33694 * @param {String} msg The message box body text
33695 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33696 * @param {Object} scope (optional) The scope of the callback function
33697 * @return {Roo.MessageBox} This message box
33699 confirm : function(title, msg, fn, scope){
33703 buttons: this.YESNO,
33712 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33713 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33714 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33715 * (could also be the top-right close button) and the text that was entered will be passed as the two
33716 * parameters to the callback.
33717 * @param {String} title The title bar text
33718 * @param {String} msg The message box body text
33719 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33720 * @param {Object} scope (optional) The scope of the callback function
33721 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33722 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33723 * @return {Roo.MessageBox} This message box
33725 prompt : function(title, msg, fn, scope, multiline){
33729 buttons: this.OKCANCEL,
33734 multiline: multiline,
33741 * Button config that displays a single OK button
33746 * Button config that displays Yes and No buttons
33749 YESNO : {yes:true, no:true},
33751 * Button config that displays OK and Cancel buttons
33754 OKCANCEL : {ok:true, cancel:true},
33756 * Button config that displays Yes, No and Cancel buttons
33759 YESNOCANCEL : {yes:true, no:true, cancel:true},
33762 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33765 defaultTextHeight : 75,
33767 * The maximum width in pixels of the message box (defaults to 600)
33772 * The minimum width in pixels of the message box (defaults to 100)
33777 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33778 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33781 minProgressWidth : 250,
33783 * An object containing the default button text strings that can be overriden for localized language support.
33784 * Supported properties are: ok, cancel, yes and no.
33785 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33798 * Shorthand for {@link Roo.MessageBox}
33800 Roo.Msg = Roo.MessageBox;/*
33802 * Ext JS Library 1.1.1
33803 * Copyright(c) 2006-2007, Ext JS, LLC.
33805 * Originally Released Under LGPL - original licence link has changed is not relivant.
33808 * <script type="text/javascript">
33811 * @class Roo.QuickTips
33812 * Provides attractive and customizable tooltips for any element.
33815 Roo.QuickTips = function(){
33816 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33817 var ce, bd, xy, dd;
33818 var visible = false, disabled = true, inited = false;
33819 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33821 var onOver = function(e){
33825 var t = e.getTarget();
33826 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33829 if(ce && t == ce.el){
33830 clearTimeout(hideProc);
33833 if(t && tagEls[t.id]){
33834 tagEls[t.id].el = t;
33835 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33838 var ttp, et = Roo.fly(t);
33839 var ns = cfg.namespace;
33840 if(tm.interceptTitles && t.title){
33843 t.removeAttribute("title");
33844 e.preventDefault();
33846 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33849 showProc = show.defer(tm.showDelay, tm, [{
33851 text: ttp.replace(/\\n/g,'<br/>'),
33852 width: et.getAttributeNS(ns, cfg.width),
33853 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33854 title: et.getAttributeNS(ns, cfg.title),
33855 cls: et.getAttributeNS(ns, cfg.cls)
33860 var onOut = function(e){
33861 clearTimeout(showProc);
33862 var t = e.getTarget();
33863 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33864 hideProc = setTimeout(hide, tm.hideDelay);
33868 var onMove = function(e){
33874 if(tm.trackMouse && ce){
33879 var onDown = function(e){
33880 clearTimeout(showProc);
33881 clearTimeout(hideProc);
33883 if(tm.hideOnClick){
33886 tm.enable.defer(100, tm);
33891 var getPad = function(){
33892 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33895 var show = function(o){
33899 clearTimeout(dismissProc);
33901 if(removeCls){ // in case manually hidden
33902 el.removeClass(removeCls);
33906 el.addClass(ce.cls);
33907 removeCls = ce.cls;
33910 tipTitle.update(ce.title);
33913 tipTitle.update('');
33916 el.dom.style.width = tm.maxWidth+'px';
33917 //tipBody.dom.style.width = '';
33918 tipBodyText.update(o.text);
33919 var p = getPad(), w = ce.width;
33921 var td = tipBodyText.dom;
33922 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33923 if(aw > tm.maxWidth){
33925 }else if(aw < tm.minWidth){
33931 //tipBody.setWidth(w);
33932 el.setWidth(parseInt(w, 10) + p);
33933 if(ce.autoHide === false){
33934 close.setDisplayed(true);
33939 close.setDisplayed(false);
33945 el.avoidY = xy[1]-18;
33950 el.setStyle("visibility", "visible");
33951 el.fadeIn({callback: afterShow});
33957 var afterShow = function(){
33961 if(tm.autoDismiss && ce.autoHide !== false){
33962 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33967 var hide = function(noanim){
33968 clearTimeout(dismissProc);
33969 clearTimeout(hideProc);
33971 if(el.isVisible()){
33973 if(noanim !== true && tm.animate){
33974 el.fadeOut({callback: afterHide});
33981 var afterHide = function(){
33984 el.removeClass(removeCls);
33991 * @cfg {Number} minWidth
33992 * The minimum width of the quick tip (defaults to 40)
33996 * @cfg {Number} maxWidth
33997 * The maximum width of the quick tip (defaults to 300)
34001 * @cfg {Boolean} interceptTitles
34002 * True to automatically use the element's DOM title value if available (defaults to false)
34004 interceptTitles : false,
34006 * @cfg {Boolean} trackMouse
34007 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34009 trackMouse : false,
34011 * @cfg {Boolean} hideOnClick
34012 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34014 hideOnClick : true,
34016 * @cfg {Number} showDelay
34017 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
34021 * @cfg {Number} hideDelay
34022 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34026 * @cfg {Boolean} autoHide
34027 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34028 * Used in conjunction with hideDelay.
34033 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34034 * (defaults to true). Used in conjunction with autoDismissDelay.
34036 autoDismiss : true,
34039 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34041 autoDismissDelay : 5000,
34043 * @cfg {Boolean} animate
34044 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34049 * @cfg {String} title
34050 * Title text to display (defaults to ''). This can be any valid HTML markup.
34054 * @cfg {String} text
34055 * Body text to display (defaults to ''). This can be any valid HTML markup.
34059 * @cfg {String} cls
34060 * A CSS class to apply to the base quick tip element (defaults to '').
34064 * @cfg {Number} width
34065 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34066 * minWidth or maxWidth.
34071 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34072 * or display QuickTips in a page.
34075 tm = Roo.QuickTips;
34076 cfg = tm.tagConfig;
34078 if(!Roo.isReady){ // allow calling of init() before onReady
34079 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34082 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34083 el.fxDefaults = {stopFx: true};
34084 // maximum custom styling
34085 //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>');
34086 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>');
34087 tipTitle = el.child('h3');
34088 tipTitle.enableDisplayMode("block");
34089 tipBody = el.child('div.x-tip-bd');
34090 tipBodyText = el.child('div.x-tip-bd-inner');
34091 //bdLeft = el.child('div.x-tip-bd-left');
34092 //bdRight = el.child('div.x-tip-bd-right');
34093 close = el.child('div.x-tip-close');
34094 close.enableDisplayMode("block");
34095 close.on("click", hide);
34096 var d = Roo.get(document);
34097 d.on("mousedown", onDown);
34098 d.on("mouseover", onOver);
34099 d.on("mouseout", onOut);
34100 d.on("mousemove", onMove);
34101 esc = d.addKeyListener(27, hide);
34104 dd = el.initDD("default", null, {
34105 onDrag : function(){
34109 dd.setHandleElId(tipTitle.id);
34118 * Configures a new quick tip instance and assigns it to a target element. The following config options
34121 Property Type Description
34122 ---------- --------------------- ------------------------------------------------------------------------
34123 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34125 * @param {Object} config The config object
34127 register : function(config){
34128 var cs = config instanceof Array ? config : arguments;
34129 for(var i = 0, len = cs.length; i < len; i++) {
34131 var target = c.target;
34133 if(target instanceof Array){
34134 for(var j = 0, jlen = target.length; j < jlen; j++){
34135 tagEls[target[j]] = c;
34138 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34145 * Removes this quick tip from its element and destroys it.
34146 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34148 unregister : function(el){
34149 delete tagEls[Roo.id(el)];
34153 * Enable this quick tip.
34155 enable : function(){
34156 if(inited && disabled){
34158 if(locks.length < 1){
34165 * Disable this quick tip.
34167 disable : function(){
34169 clearTimeout(showProc);
34170 clearTimeout(hideProc);
34171 clearTimeout(dismissProc);
34179 * Returns true if the quick tip is enabled, else false.
34181 isEnabled : function(){
34187 namespace : "roo", // was ext?? this may break..
34188 alt_namespace : "ext",
34189 attribute : "qtip",
34199 // backwards compat
34200 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34202 * Ext JS Library 1.1.1
34203 * Copyright(c) 2006-2007, Ext JS, LLC.
34205 * Originally Released Under LGPL - original licence link has changed is not relivant.
34208 * <script type="text/javascript">
34213 * @class Roo.tree.TreePanel
34214 * @extends Roo.data.Tree
34216 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34217 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34218 * @cfg {Boolean} enableDD true to enable drag and drop
34219 * @cfg {Boolean} enableDrag true to enable just drag
34220 * @cfg {Boolean} enableDrop true to enable just drop
34221 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34222 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34223 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34224 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34225 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34226 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34227 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34228 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34229 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34230 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34231 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34232 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34233 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34234 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34235 * @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>
34236 * @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>
34239 * @param {String/HTMLElement/Element} el The container element
34240 * @param {Object} config
34242 Roo.tree.TreePanel = function(el, config){
34244 var loader = false;
34246 root = config.root;
34247 delete config.root;
34249 if (config.loader) {
34250 loader = config.loader;
34251 delete config.loader;
34254 Roo.apply(this, config);
34255 Roo.tree.TreePanel.superclass.constructor.call(this);
34256 this.el = Roo.get(el);
34257 this.el.addClass('x-tree');
34258 //console.log(root);
34260 this.setRootNode( Roo.factory(root, Roo.tree));
34263 this.loader = Roo.factory(loader, Roo.tree);
34266 * Read-only. The id of the container element becomes this TreePanel's id.
34268 this.id = this.el.id;
34271 * @event beforeload
34272 * Fires before a node is loaded, return false to cancel
34273 * @param {Node} node The node being loaded
34275 "beforeload" : true,
34278 * Fires when a node is loaded
34279 * @param {Node} node The node that was loaded
34283 * @event textchange
34284 * Fires when the text for a node is changed
34285 * @param {Node} node The node
34286 * @param {String} text The new text
34287 * @param {String} oldText The old text
34289 "textchange" : true,
34291 * @event beforeexpand
34292 * Fires before a node is expanded, return false to cancel.
34293 * @param {Node} node The node
34294 * @param {Boolean} deep
34295 * @param {Boolean} anim
34297 "beforeexpand" : true,
34299 * @event beforecollapse
34300 * Fires before a node is collapsed, return false to cancel.
34301 * @param {Node} node The node
34302 * @param {Boolean} deep
34303 * @param {Boolean} anim
34305 "beforecollapse" : true,
34308 * Fires when a node is expanded
34309 * @param {Node} node The node
34313 * @event disabledchange
34314 * Fires when the disabled status of a node changes
34315 * @param {Node} node The node
34316 * @param {Boolean} disabled
34318 "disabledchange" : true,
34321 * Fires when a node is collapsed
34322 * @param {Node} node The node
34326 * @event beforeclick
34327 * Fires before click processing on a node. Return false to cancel the default action.
34328 * @param {Node} node The node
34329 * @param {Roo.EventObject} e The event object
34331 "beforeclick":true,
34333 * @event checkchange
34334 * Fires when a node with a checkbox's checked property changes
34335 * @param {Node} this This node
34336 * @param {Boolean} checked
34338 "checkchange":true,
34341 * Fires when a node is clicked
34342 * @param {Node} node The node
34343 * @param {Roo.EventObject} e The event object
34348 * Fires when a node is double clicked
34349 * @param {Node} node The node
34350 * @param {Roo.EventObject} e The event object
34354 * @event contextmenu
34355 * Fires when a node is right clicked
34356 * @param {Node} node The node
34357 * @param {Roo.EventObject} e The event object
34359 "contextmenu":true,
34361 * @event beforechildrenrendered
34362 * Fires right before the child nodes for a node are rendered
34363 * @param {Node} node The node
34365 "beforechildrenrendered":true,
34368 * Fires when a node starts being dragged
34369 * @param {Roo.tree.TreePanel} this
34370 * @param {Roo.tree.TreeNode} node
34371 * @param {event} e The raw browser event
34373 "startdrag" : true,
34376 * Fires when a drag operation is complete
34377 * @param {Roo.tree.TreePanel} this
34378 * @param {Roo.tree.TreeNode} node
34379 * @param {event} e The raw browser event
34384 * Fires when a dragged node is dropped on a valid DD target
34385 * @param {Roo.tree.TreePanel} this
34386 * @param {Roo.tree.TreeNode} node
34387 * @param {DD} dd The dd it was dropped on
34388 * @param {event} e The raw browser event
34392 * @event beforenodedrop
34393 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34394 * passed to handlers has the following properties:<br />
34395 * <ul style="padding:5px;padding-left:16px;">
34396 * <li>tree - The TreePanel</li>
34397 * <li>target - The node being targeted for the drop</li>
34398 * <li>data - The drag data from the drag source</li>
34399 * <li>point - The point of the drop - append, above or below</li>
34400 * <li>source - The drag source</li>
34401 * <li>rawEvent - Raw mouse event</li>
34402 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34403 * to be inserted by setting them on this object.</li>
34404 * <li>cancel - Set this to true to cancel the drop.</li>
34406 * @param {Object} dropEvent
34408 "beforenodedrop" : true,
34411 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34412 * passed to handlers has the following properties:<br />
34413 * <ul style="padding:5px;padding-left:16px;">
34414 * <li>tree - The TreePanel</li>
34415 * <li>target - The node being targeted for the drop</li>
34416 * <li>data - The drag data from the drag source</li>
34417 * <li>point - The point of the drop - append, above or below</li>
34418 * <li>source - The drag source</li>
34419 * <li>rawEvent - Raw mouse event</li>
34420 * <li>dropNode - Dropped node(s).</li>
34422 * @param {Object} dropEvent
34426 * @event nodedragover
34427 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34428 * passed to handlers has the following properties:<br />
34429 * <ul style="padding:5px;padding-left:16px;">
34430 * <li>tree - The TreePanel</li>
34431 * <li>target - The node being targeted for the drop</li>
34432 * <li>data - The drag data from the drag source</li>
34433 * <li>point - The point of the drop - append, above or below</li>
34434 * <li>source - The drag source</li>
34435 * <li>rawEvent - Raw mouse event</li>
34436 * <li>dropNode - Drop node(s) provided by the source.</li>
34437 * <li>cancel - Set this to true to signal drop not allowed.</li>
34439 * @param {Object} dragOverEvent
34441 "nodedragover" : true,
34443 * @event appendnode
34444 * Fires when append node to the tree
34445 * @param {Roo.tree.TreePanel} this
34446 * @param {Roo.tree.TreeNode} node
34447 * @param {Number} index The index of the newly appended node
34449 "appendnode" : true
34452 if(this.singleExpand){
34453 this.on("beforeexpand", this.restrictExpand, this);
34456 this.editor.tree = this;
34457 this.editor = Roo.factory(this.editor, Roo.tree);
34460 if (this.selModel) {
34461 this.selModel = Roo.factory(this.selModel, Roo.tree);
34465 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34466 rootVisible : true,
34467 animate: Roo.enableFx,
34470 hlDrop : Roo.enableFx,
34474 rendererTip: false,
34476 restrictExpand : function(node){
34477 var p = node.parentNode;
34479 if(p.expandedChild && p.expandedChild.parentNode == p){
34480 p.expandedChild.collapse();
34482 p.expandedChild = node;
34486 // private override
34487 setRootNode : function(node){
34488 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34489 if(!this.rootVisible){
34490 node.ui = new Roo.tree.RootTreeNodeUI(node);
34496 * Returns the container element for this TreePanel
34498 getEl : function(){
34503 * Returns the default TreeLoader for this TreePanel
34505 getLoader : function(){
34506 return this.loader;
34512 expandAll : function(){
34513 this.root.expand(true);
34517 * Collapse all nodes
34519 collapseAll : function(){
34520 this.root.collapse(true);
34524 * Returns the selection model used by this TreePanel
34526 getSelectionModel : function(){
34527 if(!this.selModel){
34528 this.selModel = new Roo.tree.DefaultSelectionModel();
34530 return this.selModel;
34534 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34535 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34536 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34539 getChecked : function(a, startNode){
34540 startNode = startNode || this.root;
34542 var f = function(){
34543 if(this.attributes.checked){
34544 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34547 startNode.cascade(f);
34552 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34553 * @param {String} path
34554 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34555 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34556 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34558 expandPath : function(path, attr, callback){
34559 attr = attr || "id";
34560 var keys = path.split(this.pathSeparator);
34561 var curNode = this.root;
34562 if(curNode.attributes[attr] != keys[1]){ // invalid root
34564 callback(false, null);
34569 var f = function(){
34570 if(++index == keys.length){
34572 callback(true, curNode);
34576 var c = curNode.findChild(attr, keys[index]);
34579 callback(false, curNode);
34584 c.expand(false, false, f);
34586 curNode.expand(false, false, f);
34590 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34591 * @param {String} path
34592 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34593 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34594 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34596 selectPath : function(path, attr, callback){
34597 attr = attr || "id";
34598 var keys = path.split(this.pathSeparator);
34599 var v = keys.pop();
34600 if(keys.length > 0){
34601 var f = function(success, node){
34602 if(success && node){
34603 var n = node.findChild(attr, v);
34609 }else if(callback){
34610 callback(false, n);
34614 callback(false, n);
34618 this.expandPath(keys.join(this.pathSeparator), attr, f);
34620 this.root.select();
34622 callback(true, this.root);
34627 getTreeEl : function(){
34632 * Trigger rendering of this TreePanel
34634 render : function(){
34635 if (this.innerCt) {
34636 return this; // stop it rendering more than once!!
34639 this.innerCt = this.el.createChild({tag:"ul",
34640 cls:"x-tree-root-ct " +
34641 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34643 if(this.containerScroll){
34644 Roo.dd.ScrollManager.register(this.el);
34646 if((this.enableDD || this.enableDrop) && !this.dropZone){
34648 * The dropZone used by this tree if drop is enabled
34649 * @type Roo.tree.TreeDropZone
34651 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34652 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34655 if((this.enableDD || this.enableDrag) && !this.dragZone){
34657 * The dragZone used by this tree if drag is enabled
34658 * @type Roo.tree.TreeDragZone
34660 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34661 ddGroup: this.ddGroup || "TreeDD",
34662 scroll: this.ddScroll
34665 this.getSelectionModel().init(this);
34667 Roo.log("ROOT not set in tree");
34670 this.root.render();
34671 if(!this.rootVisible){
34672 this.root.renderChildren();
34678 * Ext JS Library 1.1.1
34679 * Copyright(c) 2006-2007, Ext JS, LLC.
34681 * Originally Released Under LGPL - original licence link has changed is not relivant.
34684 * <script type="text/javascript">
34689 * @class Roo.tree.DefaultSelectionModel
34690 * @extends Roo.util.Observable
34691 * The default single selection for a TreePanel.
34692 * @param {Object} cfg Configuration
34694 Roo.tree.DefaultSelectionModel = function(cfg){
34695 this.selNode = null;
34701 * @event selectionchange
34702 * Fires when the selected node changes
34703 * @param {DefaultSelectionModel} this
34704 * @param {TreeNode} node the new selection
34706 "selectionchange" : true,
34709 * @event beforeselect
34710 * Fires before the selected node changes, return false to cancel the change
34711 * @param {DefaultSelectionModel} this
34712 * @param {TreeNode} node the new selection
34713 * @param {TreeNode} node the old selection
34715 "beforeselect" : true
34718 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34721 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34722 init : function(tree){
34724 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34725 tree.on("click", this.onNodeClick, this);
34728 onNodeClick : function(node, e){
34729 if (e.ctrlKey && this.selNode == node) {
34730 this.unselect(node);
34738 * @param {TreeNode} node The node to select
34739 * @return {TreeNode} The selected node
34741 select : function(node){
34742 var last = this.selNode;
34743 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34745 last.ui.onSelectedChange(false);
34747 this.selNode = node;
34748 node.ui.onSelectedChange(true);
34749 this.fireEvent("selectionchange", this, node, last);
34756 * @param {TreeNode} node The node to unselect
34758 unselect : function(node){
34759 if(this.selNode == node){
34760 this.clearSelections();
34765 * Clear all selections
34767 clearSelections : function(){
34768 var n = this.selNode;
34770 n.ui.onSelectedChange(false);
34771 this.selNode = null;
34772 this.fireEvent("selectionchange", this, null);
34778 * Get the selected node
34779 * @return {TreeNode} The selected node
34781 getSelectedNode : function(){
34782 return this.selNode;
34786 * Returns true if the node is selected
34787 * @param {TreeNode} node The node to check
34788 * @return {Boolean}
34790 isSelected : function(node){
34791 return this.selNode == node;
34795 * Selects the node above the selected node in the tree, intelligently walking the nodes
34796 * @return TreeNode The new selection
34798 selectPrevious : function(){
34799 var s = this.selNode || this.lastSelNode;
34803 var ps = s.previousSibling;
34805 if(!ps.isExpanded() || ps.childNodes.length < 1){
34806 return this.select(ps);
34808 var lc = ps.lastChild;
34809 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34812 return this.select(lc);
34814 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34815 return this.select(s.parentNode);
34821 * Selects the node above the selected node in the tree, intelligently walking the nodes
34822 * @return TreeNode The new selection
34824 selectNext : function(){
34825 var s = this.selNode || this.lastSelNode;
34829 if(s.firstChild && s.isExpanded()){
34830 return this.select(s.firstChild);
34831 }else if(s.nextSibling){
34832 return this.select(s.nextSibling);
34833 }else if(s.parentNode){
34835 s.parentNode.bubble(function(){
34836 if(this.nextSibling){
34837 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34846 onKeyDown : function(e){
34847 var s = this.selNode || this.lastSelNode;
34848 // undesirable, but required
34853 var k = e.getKey();
34861 this.selectPrevious();
34864 e.preventDefault();
34865 if(s.hasChildNodes()){
34866 if(!s.isExpanded()){
34868 }else if(s.firstChild){
34869 this.select(s.firstChild, e);
34874 e.preventDefault();
34875 if(s.hasChildNodes() && s.isExpanded()){
34877 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34878 this.select(s.parentNode, e);
34886 * @class Roo.tree.MultiSelectionModel
34887 * @extends Roo.util.Observable
34888 * Multi selection for a TreePanel.
34889 * @param {Object} cfg Configuration
34891 Roo.tree.MultiSelectionModel = function(){
34892 this.selNodes = [];
34896 * @event selectionchange
34897 * Fires when the selected nodes change
34898 * @param {MultiSelectionModel} this
34899 * @param {Array} nodes Array of the selected nodes
34901 "selectionchange" : true
34903 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34907 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34908 init : function(tree){
34910 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34911 tree.on("click", this.onNodeClick, this);
34914 onNodeClick : function(node, e){
34915 this.select(node, e, e.ctrlKey);
34920 * @param {TreeNode} node The node to select
34921 * @param {EventObject} e (optional) An event associated with the selection
34922 * @param {Boolean} keepExisting True to retain existing selections
34923 * @return {TreeNode} The selected node
34925 select : function(node, e, keepExisting){
34926 if(keepExisting !== true){
34927 this.clearSelections(true);
34929 if(this.isSelected(node)){
34930 this.lastSelNode = node;
34933 this.selNodes.push(node);
34934 this.selMap[node.id] = node;
34935 this.lastSelNode = node;
34936 node.ui.onSelectedChange(true);
34937 this.fireEvent("selectionchange", this, this.selNodes);
34943 * @param {TreeNode} node The node to unselect
34945 unselect : function(node){
34946 if(this.selMap[node.id]){
34947 node.ui.onSelectedChange(false);
34948 var sn = this.selNodes;
34951 index = sn.indexOf(node);
34953 for(var i = 0, len = sn.length; i < len; i++){
34961 this.selNodes.splice(index, 1);
34963 delete this.selMap[node.id];
34964 this.fireEvent("selectionchange", this, this.selNodes);
34969 * Clear all selections
34971 clearSelections : function(suppressEvent){
34972 var sn = this.selNodes;
34974 for(var i = 0, len = sn.length; i < len; i++){
34975 sn[i].ui.onSelectedChange(false);
34977 this.selNodes = [];
34979 if(suppressEvent !== true){
34980 this.fireEvent("selectionchange", this, this.selNodes);
34986 * Returns true if the node is selected
34987 * @param {TreeNode} node The node to check
34988 * @return {Boolean}
34990 isSelected : function(node){
34991 return this.selMap[node.id] ? true : false;
34995 * Returns an array of the selected nodes
34998 getSelectedNodes : function(){
34999 return this.selNodes;
35002 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35004 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35006 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35009 * Ext JS Library 1.1.1
35010 * Copyright(c) 2006-2007, Ext JS, LLC.
35012 * Originally Released Under LGPL - original licence link has changed is not relivant.
35015 * <script type="text/javascript">
35019 * @class Roo.tree.TreeNode
35020 * @extends Roo.data.Node
35021 * @cfg {String} text The text for this node
35022 * @cfg {Boolean} expanded true to start the node expanded
35023 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35024 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35025 * @cfg {Boolean} disabled true to start the node disabled
35026 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35027 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35028 * @cfg {String} cls A css class to be added to the node
35029 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35030 * @cfg {String} href URL of the link used for the node (defaults to #)
35031 * @cfg {String} hrefTarget target frame for the link
35032 * @cfg {String} qtip An Ext QuickTip for the node
35033 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35034 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35035 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35036 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35037 * (defaults to undefined with no checkbox rendered)
35039 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35041 Roo.tree.TreeNode = function(attributes){
35042 attributes = attributes || {};
35043 if(typeof attributes == "string"){
35044 attributes = {text: attributes};
35046 this.childrenRendered = false;
35047 this.rendered = false;
35048 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35049 this.expanded = attributes.expanded === true;
35050 this.isTarget = attributes.isTarget !== false;
35051 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35052 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35055 * Read-only. The text for this node. To change it use setText().
35058 this.text = attributes.text;
35060 * True if this node is disabled.
35063 this.disabled = attributes.disabled === true;
35067 * @event textchange
35068 * Fires when the text for this node is changed
35069 * @param {Node} this This node
35070 * @param {String} text The new text
35071 * @param {String} oldText The old text
35073 "textchange" : true,
35075 * @event beforeexpand
35076 * Fires before this node is expanded, return false to cancel.
35077 * @param {Node} this This node
35078 * @param {Boolean} deep
35079 * @param {Boolean} anim
35081 "beforeexpand" : true,
35083 * @event beforecollapse
35084 * Fires before this node is collapsed, return false to cancel.
35085 * @param {Node} this This node
35086 * @param {Boolean} deep
35087 * @param {Boolean} anim
35089 "beforecollapse" : true,
35092 * Fires when this node is expanded
35093 * @param {Node} this This node
35097 * @event disabledchange
35098 * Fires when the disabled status of this node changes
35099 * @param {Node} this This node
35100 * @param {Boolean} disabled
35102 "disabledchange" : true,
35105 * Fires when this node is collapsed
35106 * @param {Node} this This node
35110 * @event beforeclick
35111 * Fires before click processing. Return false to cancel the default action.
35112 * @param {Node} this This node
35113 * @param {Roo.EventObject} e The event object
35115 "beforeclick":true,
35117 * @event checkchange
35118 * Fires when a node with a checkbox's checked property changes
35119 * @param {Node} this This node
35120 * @param {Boolean} checked
35122 "checkchange":true,
35125 * Fires when this node is clicked
35126 * @param {Node} this This node
35127 * @param {Roo.EventObject} e The event object
35132 * Fires when this node is double clicked
35133 * @param {Node} this This node
35134 * @param {Roo.EventObject} e The event object
35138 * @event contextmenu
35139 * Fires when this node is right clicked
35140 * @param {Node} this This node
35141 * @param {Roo.EventObject} e The event object
35143 "contextmenu":true,
35145 * @event beforechildrenrendered
35146 * Fires right before the child nodes for this node are rendered
35147 * @param {Node} this This node
35149 "beforechildrenrendered":true
35152 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35155 * Read-only. The UI for this node
35158 this.ui = new uiClass(this);
35160 // finally support items[]
35161 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35166 Roo.each(this.attributes.items, function(c) {
35167 this.appendChild(Roo.factory(c,Roo.Tree));
35169 delete this.attributes.items;
35174 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35175 preventHScroll: true,
35177 * Returns true if this node is expanded
35178 * @return {Boolean}
35180 isExpanded : function(){
35181 return this.expanded;
35185 * Returns the UI object for this node
35186 * @return {TreeNodeUI}
35188 getUI : function(){
35192 // private override
35193 setFirstChild : function(node){
35194 var of = this.firstChild;
35195 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35196 if(this.childrenRendered && of && node != of){
35197 of.renderIndent(true, true);
35200 this.renderIndent(true, true);
35204 // private override
35205 setLastChild : function(node){
35206 var ol = this.lastChild;
35207 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35208 if(this.childrenRendered && ol && node != ol){
35209 ol.renderIndent(true, true);
35212 this.renderIndent(true, true);
35216 // these methods are overridden to provide lazy rendering support
35217 // private override
35218 appendChild : function()
35220 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35221 if(node && this.childrenRendered){
35224 this.ui.updateExpandIcon();
35228 // private override
35229 removeChild : function(node){
35230 this.ownerTree.getSelectionModel().unselect(node);
35231 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35232 // if it's been rendered remove dom node
35233 if(this.childrenRendered){
35236 if(this.childNodes.length < 1){
35237 this.collapse(false, false);
35239 this.ui.updateExpandIcon();
35241 if(!this.firstChild) {
35242 this.childrenRendered = false;
35247 // private override
35248 insertBefore : function(node, refNode){
35249 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35250 if(newNode && refNode && this.childrenRendered){
35253 this.ui.updateExpandIcon();
35258 * Sets the text for this node
35259 * @param {String} text
35261 setText : function(text){
35262 var oldText = this.text;
35264 this.attributes.text = text;
35265 if(this.rendered){ // event without subscribing
35266 this.ui.onTextChange(this, text, oldText);
35268 this.fireEvent("textchange", this, text, oldText);
35272 * Triggers selection of this node
35274 select : function(){
35275 this.getOwnerTree().getSelectionModel().select(this);
35279 * Triggers deselection of this node
35281 unselect : function(){
35282 this.getOwnerTree().getSelectionModel().unselect(this);
35286 * Returns true if this node is selected
35287 * @return {Boolean}
35289 isSelected : function(){
35290 return this.getOwnerTree().getSelectionModel().isSelected(this);
35294 * Expand this node.
35295 * @param {Boolean} deep (optional) True to expand all children as well
35296 * @param {Boolean} anim (optional) false to cancel the default animation
35297 * @param {Function} callback (optional) A callback to be called when
35298 * expanding this node completes (does not wait for deep expand to complete).
35299 * Called with 1 parameter, this node.
35301 expand : function(deep, anim, callback){
35302 if(!this.expanded){
35303 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35306 if(!this.childrenRendered){
35307 this.renderChildren();
35309 this.expanded = true;
35311 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35312 this.ui.animExpand(function(){
35313 this.fireEvent("expand", this);
35314 if(typeof callback == "function"){
35318 this.expandChildNodes(true);
35320 }.createDelegate(this));
35324 this.fireEvent("expand", this);
35325 if(typeof callback == "function"){
35330 if(typeof callback == "function"){
35335 this.expandChildNodes(true);
35339 isHiddenRoot : function(){
35340 return this.isRoot && !this.getOwnerTree().rootVisible;
35344 * Collapse this node.
35345 * @param {Boolean} deep (optional) True to collapse all children as well
35346 * @param {Boolean} anim (optional) false to cancel the default animation
35348 collapse : function(deep, anim){
35349 if(this.expanded && !this.isHiddenRoot()){
35350 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35353 this.expanded = false;
35354 if((this.getOwnerTree().animate && anim !== false) || anim){
35355 this.ui.animCollapse(function(){
35356 this.fireEvent("collapse", this);
35358 this.collapseChildNodes(true);
35360 }.createDelegate(this));
35363 this.ui.collapse();
35364 this.fireEvent("collapse", this);
35368 var cs = this.childNodes;
35369 for(var i = 0, len = cs.length; i < len; i++) {
35370 cs[i].collapse(true, false);
35376 delayedExpand : function(delay){
35377 if(!this.expandProcId){
35378 this.expandProcId = this.expand.defer(delay, this);
35383 cancelExpand : function(){
35384 if(this.expandProcId){
35385 clearTimeout(this.expandProcId);
35387 this.expandProcId = false;
35391 * Toggles expanded/collapsed state of the node
35393 toggle : function(){
35402 * Ensures all parent nodes are expanded
35404 ensureVisible : function(callback){
35405 var tree = this.getOwnerTree();
35406 tree.expandPath(this.parentNode.getPath(), false, function(){
35407 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35408 Roo.callback(callback);
35409 }.createDelegate(this));
35413 * Expand all child nodes
35414 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35416 expandChildNodes : function(deep){
35417 var cs = this.childNodes;
35418 for(var i = 0, len = cs.length; i < len; i++) {
35419 cs[i].expand(deep);
35424 * Collapse all child nodes
35425 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35427 collapseChildNodes : function(deep){
35428 var cs = this.childNodes;
35429 for(var i = 0, len = cs.length; i < len; i++) {
35430 cs[i].collapse(deep);
35435 * Disables this node
35437 disable : function(){
35438 this.disabled = true;
35440 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35441 this.ui.onDisableChange(this, true);
35443 this.fireEvent("disabledchange", this, true);
35447 * Enables this node
35449 enable : function(){
35450 this.disabled = false;
35451 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35452 this.ui.onDisableChange(this, false);
35454 this.fireEvent("disabledchange", this, false);
35458 renderChildren : function(suppressEvent){
35459 if(suppressEvent !== false){
35460 this.fireEvent("beforechildrenrendered", this);
35462 var cs = this.childNodes;
35463 for(var i = 0, len = cs.length; i < len; i++){
35464 cs[i].render(true);
35466 this.childrenRendered = true;
35470 sort : function(fn, scope){
35471 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35472 if(this.childrenRendered){
35473 var cs = this.childNodes;
35474 for(var i = 0, len = cs.length; i < len; i++){
35475 cs[i].render(true);
35481 render : function(bulkRender){
35482 this.ui.render(bulkRender);
35483 if(!this.rendered){
35484 this.rendered = true;
35486 this.expanded = false;
35487 this.expand(false, false);
35493 renderIndent : function(deep, refresh){
35495 this.ui.childIndent = null;
35497 this.ui.renderIndent();
35498 if(deep === true && this.childrenRendered){
35499 var cs = this.childNodes;
35500 for(var i = 0, len = cs.length; i < len; i++){
35501 cs[i].renderIndent(true, refresh);
35507 * Ext JS Library 1.1.1
35508 * Copyright(c) 2006-2007, Ext JS, LLC.
35510 * Originally Released Under LGPL - original licence link has changed is not relivant.
35513 * <script type="text/javascript">
35517 * @class Roo.tree.AsyncTreeNode
35518 * @extends Roo.tree.TreeNode
35519 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35521 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35523 Roo.tree.AsyncTreeNode = function(config){
35524 this.loaded = false;
35525 this.loading = false;
35526 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35528 * @event beforeload
35529 * Fires before this node is loaded, return false to cancel
35530 * @param {Node} this This node
35532 this.addEvents({'beforeload':true, 'load': true});
35535 * Fires when this node is loaded
35536 * @param {Node} this This node
35539 * The loader used by this node (defaults to using the tree's defined loader)
35544 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35545 expand : function(deep, anim, callback){
35546 if(this.loading){ // if an async load is already running, waiting til it's done
35548 var f = function(){
35549 if(!this.loading){ // done loading
35550 clearInterval(timer);
35551 this.expand(deep, anim, callback);
35553 }.createDelegate(this);
35554 timer = setInterval(f, 200);
35558 if(this.fireEvent("beforeload", this) === false){
35561 this.loading = true;
35562 this.ui.beforeLoad(this);
35563 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35565 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35569 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35573 * Returns true if this node is currently loading
35574 * @return {Boolean}
35576 isLoading : function(){
35577 return this.loading;
35580 loadComplete : function(deep, anim, callback){
35581 this.loading = false;
35582 this.loaded = true;
35583 this.ui.afterLoad(this);
35584 this.fireEvent("load", this);
35585 this.expand(deep, anim, callback);
35589 * Returns true if this node has been loaded
35590 * @return {Boolean}
35592 isLoaded : function(){
35593 return this.loaded;
35596 hasChildNodes : function(){
35597 if(!this.isLeaf() && !this.loaded){
35600 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35605 * Trigger a reload for this node
35606 * @param {Function} callback
35608 reload : function(callback){
35609 this.collapse(false, false);
35610 while(this.firstChild){
35611 this.removeChild(this.firstChild);
35613 this.childrenRendered = false;
35614 this.loaded = false;
35615 if(this.isHiddenRoot()){
35616 this.expanded = false;
35618 this.expand(false, false, callback);
35622 * Ext JS Library 1.1.1
35623 * Copyright(c) 2006-2007, Ext JS, LLC.
35625 * Originally Released Under LGPL - original licence link has changed is not relivant.
35628 * <script type="text/javascript">
35632 * @class Roo.tree.TreeNodeUI
35634 * @param {Object} node The node to render
35635 * The TreeNode UI implementation is separate from the
35636 * tree implementation. Unless you are customizing the tree UI,
35637 * you should never have to use this directly.
35639 Roo.tree.TreeNodeUI = function(node){
35641 this.rendered = false;
35642 this.animating = false;
35643 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35646 Roo.tree.TreeNodeUI.prototype = {
35647 removeChild : function(node){
35649 this.ctNode.removeChild(node.ui.getEl());
35653 beforeLoad : function(){
35654 this.addClass("x-tree-node-loading");
35657 afterLoad : function(){
35658 this.removeClass("x-tree-node-loading");
35661 onTextChange : function(node, text, oldText){
35663 this.textNode.innerHTML = text;
35667 onDisableChange : function(node, state){
35668 this.disabled = state;
35670 this.addClass("x-tree-node-disabled");
35672 this.removeClass("x-tree-node-disabled");
35676 onSelectedChange : function(state){
35679 this.addClass("x-tree-selected");
35682 this.removeClass("x-tree-selected");
35686 onMove : function(tree, node, oldParent, newParent, index, refNode){
35687 this.childIndent = null;
35689 var targetNode = newParent.ui.getContainer();
35690 if(!targetNode){//target not rendered
35691 this.holder = document.createElement("div");
35692 this.holder.appendChild(this.wrap);
35695 var insertBefore = refNode ? refNode.ui.getEl() : null;
35697 targetNode.insertBefore(this.wrap, insertBefore);
35699 targetNode.appendChild(this.wrap);
35701 this.node.renderIndent(true);
35705 addClass : function(cls){
35707 Roo.fly(this.elNode).addClass(cls);
35711 removeClass : function(cls){
35713 Roo.fly(this.elNode).removeClass(cls);
35717 remove : function(){
35719 this.holder = document.createElement("div");
35720 this.holder.appendChild(this.wrap);
35724 fireEvent : function(){
35725 return this.node.fireEvent.apply(this.node, arguments);
35728 initEvents : function(){
35729 this.node.on("move", this.onMove, this);
35730 var E = Roo.EventManager;
35731 var a = this.anchor;
35733 var el = Roo.fly(a, '_treeui');
35735 if(Roo.isOpera){ // opera render bug ignores the CSS
35736 el.setStyle("text-decoration", "none");
35739 el.on("click", this.onClick, this);
35740 el.on("dblclick", this.onDblClick, this);
35743 Roo.EventManager.on(this.checkbox,
35744 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35747 el.on("contextmenu", this.onContextMenu, this);
35749 var icon = Roo.fly(this.iconNode);
35750 icon.on("click", this.onClick, this);
35751 icon.on("dblclick", this.onDblClick, this);
35752 icon.on("contextmenu", this.onContextMenu, this);
35753 E.on(this.ecNode, "click", this.ecClick, this, true);
35755 if(this.node.disabled){
35756 this.addClass("x-tree-node-disabled");
35758 if(this.node.hidden){
35759 this.addClass("x-tree-node-disabled");
35761 var ot = this.node.getOwnerTree();
35762 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35763 if(dd && (!this.node.isRoot || ot.rootVisible)){
35764 Roo.dd.Registry.register(this.elNode, {
35766 handles: this.getDDHandles(),
35772 getDDHandles : function(){
35773 return [this.iconNode, this.textNode];
35778 this.wrap.style.display = "none";
35784 this.wrap.style.display = "";
35788 onContextMenu : function(e){
35789 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35790 e.preventDefault();
35792 this.fireEvent("contextmenu", this.node, e);
35796 onClick : function(e){
35801 if(this.fireEvent("beforeclick", this.node, e) !== false){
35802 if(!this.disabled && this.node.attributes.href){
35803 this.fireEvent("click", this.node, e);
35806 e.preventDefault();
35811 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35812 this.node.toggle();
35815 this.fireEvent("click", this.node, e);
35821 onDblClick : function(e){
35822 e.preventDefault();
35827 this.toggleCheck();
35829 if(!this.animating && this.node.hasChildNodes()){
35830 this.node.toggle();
35832 this.fireEvent("dblclick", this.node, e);
35835 onCheckChange : function(){
35836 var checked = this.checkbox.checked;
35837 this.node.attributes.checked = checked;
35838 this.fireEvent('checkchange', this.node, checked);
35841 ecClick : function(e){
35842 if(!this.animating && this.node.hasChildNodes()){
35843 this.node.toggle();
35847 startDrop : function(){
35848 this.dropping = true;
35851 // delayed drop so the click event doesn't get fired on a drop
35852 endDrop : function(){
35853 setTimeout(function(){
35854 this.dropping = false;
35855 }.createDelegate(this), 50);
35858 expand : function(){
35859 this.updateExpandIcon();
35860 this.ctNode.style.display = "";
35863 focus : function(){
35864 if(!this.node.preventHScroll){
35865 try{this.anchor.focus();
35867 }else if(!Roo.isIE){
35869 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35870 var l = noscroll.scrollLeft;
35871 this.anchor.focus();
35872 noscroll.scrollLeft = l;
35877 toggleCheck : function(value){
35878 var cb = this.checkbox;
35880 cb.checked = (value === undefined ? !cb.checked : value);
35886 this.anchor.blur();
35890 animExpand : function(callback){
35891 var ct = Roo.get(this.ctNode);
35893 if(!this.node.hasChildNodes()){
35894 this.updateExpandIcon();
35895 this.ctNode.style.display = "";
35896 Roo.callback(callback);
35899 this.animating = true;
35900 this.updateExpandIcon();
35903 callback : function(){
35904 this.animating = false;
35905 Roo.callback(callback);
35908 duration: this.node.ownerTree.duration || .25
35912 highlight : function(){
35913 var tree = this.node.getOwnerTree();
35914 Roo.fly(this.wrap).highlight(
35915 tree.hlColor || "C3DAF9",
35916 {endColor: tree.hlBaseColor}
35920 collapse : function(){
35921 this.updateExpandIcon();
35922 this.ctNode.style.display = "none";
35925 animCollapse : function(callback){
35926 var ct = Roo.get(this.ctNode);
35927 ct.enableDisplayMode('block');
35930 this.animating = true;
35931 this.updateExpandIcon();
35934 callback : function(){
35935 this.animating = false;
35936 Roo.callback(callback);
35939 duration: this.node.ownerTree.duration || .25
35943 getContainer : function(){
35944 return this.ctNode;
35947 getEl : function(){
35951 appendDDGhost : function(ghostNode){
35952 ghostNode.appendChild(this.elNode.cloneNode(true));
35955 getDDRepairXY : function(){
35956 return Roo.lib.Dom.getXY(this.iconNode);
35959 onRender : function(){
35963 render : function(bulkRender){
35964 var n = this.node, a = n.attributes;
35965 var targetNode = n.parentNode ?
35966 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35968 if(!this.rendered){
35969 this.rendered = true;
35971 this.renderElements(n, a, targetNode, bulkRender);
35974 if(this.textNode.setAttributeNS){
35975 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35977 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35980 this.textNode.setAttribute("ext:qtip", a.qtip);
35982 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35985 }else if(a.qtipCfg){
35986 a.qtipCfg.target = Roo.id(this.textNode);
35987 Roo.QuickTips.register(a.qtipCfg);
35990 if(!this.node.expanded){
35991 this.updateExpandIcon();
35994 if(bulkRender === true) {
35995 targetNode.appendChild(this.wrap);
36000 renderElements : function(n, a, targetNode, bulkRender)
36002 // add some indent caching, this helps performance when rendering a large tree
36003 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36004 var t = n.getOwnerTree();
36005 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36006 if (typeof(n.attributes.html) != 'undefined') {
36007 txt = n.attributes.html;
36009 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36010 var cb = typeof a.checked == 'boolean';
36011 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36012 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36013 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36014 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36015 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
36016 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
36017 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
36018 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
36019 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
36020 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36023 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36024 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36025 n.nextSibling.ui.getEl(), buf.join(""));
36027 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36030 this.elNode = this.wrap.childNodes[0];
36031 this.ctNode = this.wrap.childNodes[1];
36032 var cs = this.elNode.childNodes;
36033 this.indentNode = cs[0];
36034 this.ecNode = cs[1];
36035 this.iconNode = cs[2];
36038 this.checkbox = cs[3];
36041 this.anchor = cs[index];
36042 this.textNode = cs[index].firstChild;
36045 getAnchor : function(){
36046 return this.anchor;
36049 getTextEl : function(){
36050 return this.textNode;
36053 getIconEl : function(){
36054 return this.iconNode;
36057 isChecked : function(){
36058 return this.checkbox ? this.checkbox.checked : false;
36061 updateExpandIcon : function(){
36063 var n = this.node, c1, c2;
36064 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36065 var hasChild = n.hasChildNodes();
36069 c1 = "x-tree-node-collapsed";
36070 c2 = "x-tree-node-expanded";
36073 c1 = "x-tree-node-expanded";
36074 c2 = "x-tree-node-collapsed";
36077 this.removeClass("x-tree-node-leaf");
36078 this.wasLeaf = false;
36080 if(this.c1 != c1 || this.c2 != c2){
36081 Roo.fly(this.elNode).replaceClass(c1, c2);
36082 this.c1 = c1; this.c2 = c2;
36085 // this changes non-leafs into leafs if they have no children.
36086 // it's not very rational behaviour..
36088 if(!this.wasLeaf && this.node.leaf){
36089 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36092 this.wasLeaf = true;
36095 var ecc = "x-tree-ec-icon "+cls;
36096 if(this.ecc != ecc){
36097 this.ecNode.className = ecc;
36103 getChildIndent : function(){
36104 if(!this.childIndent){
36108 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36110 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36112 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36117 this.childIndent = buf.join("");
36119 return this.childIndent;
36122 renderIndent : function(){
36125 var p = this.node.parentNode;
36127 indent = p.ui.getChildIndent();
36129 if(this.indentMarkup != indent){ // don't rerender if not required
36130 this.indentNode.innerHTML = indent;
36131 this.indentMarkup = indent;
36133 this.updateExpandIcon();
36138 Roo.tree.RootTreeNodeUI = function(){
36139 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36141 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36142 render : function(){
36143 if(!this.rendered){
36144 var targetNode = this.node.ownerTree.innerCt.dom;
36145 this.node.expanded = true;
36146 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36147 this.wrap = this.ctNode = targetNode.firstChild;
36150 collapse : function(){
36152 expand : function(){
36156 * Ext JS Library 1.1.1
36157 * Copyright(c) 2006-2007, Ext JS, LLC.
36159 * Originally Released Under LGPL - original licence link has changed is not relivant.
36162 * <script type="text/javascript">
36165 * @class Roo.tree.TreeLoader
36166 * @extends Roo.util.Observable
36167 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36168 * nodes from a specified URL. The response must be a javascript Array definition
36169 * who's elements are node definition objects. eg:
36174 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36175 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36182 * The old style respose with just an array is still supported, but not recommended.
36185 * A server request is sent, and child nodes are loaded only when a node is expanded.
36186 * The loading node's id is passed to the server under the parameter name "node" to
36187 * enable the server to produce the correct child nodes.
36189 * To pass extra parameters, an event handler may be attached to the "beforeload"
36190 * event, and the parameters specified in the TreeLoader's baseParams property:
36192 myTreeLoader.on("beforeload", function(treeLoader, node) {
36193 this.baseParams.category = node.attributes.category;
36198 * This would pass an HTTP parameter called "category" to the server containing
36199 * the value of the Node's "category" attribute.
36201 * Creates a new Treeloader.
36202 * @param {Object} config A config object containing config properties.
36204 Roo.tree.TreeLoader = function(config){
36205 this.baseParams = {};
36206 this.requestMethod = "POST";
36207 Roo.apply(this, config);
36212 * @event beforeload
36213 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36214 * @param {Object} This TreeLoader object.
36215 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36216 * @param {Object} callback The callback function specified in the {@link #load} call.
36221 * Fires when the node has been successfuly loaded.
36222 * @param {Object} This TreeLoader object.
36223 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36224 * @param {Object} response The response object containing the data from the server.
36228 * @event loadexception
36229 * Fires if the network request failed.
36230 * @param {Object} This TreeLoader object.
36231 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36232 * @param {Object} response The response object containing the data from the server.
36234 loadexception : true,
36237 * Fires before a node is created, enabling you to return custom Node types
36238 * @param {Object} This TreeLoader object.
36239 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36244 Roo.tree.TreeLoader.superclass.constructor.call(this);
36247 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36249 * @cfg {String} dataUrl The URL from which to request a Json string which
36250 * specifies an array of node definition object representing the child nodes
36254 * @cfg {String} requestMethod either GET or POST
36255 * defaults to POST (due to BC)
36259 * @cfg {Object} baseParams (optional) An object containing properties which
36260 * specify HTTP parameters to be passed to each request for child nodes.
36263 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36264 * created by this loader. If the attributes sent by the server have an attribute in this object,
36265 * they take priority.
36268 * @cfg {Object} uiProviders (optional) An object containing properties which
36270 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36271 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36272 * <i>uiProvider</i> attribute of a returned child node is a string rather
36273 * than a reference to a TreeNodeUI implementation, this that string value
36274 * is used as a property name in the uiProviders object. You can define the provider named
36275 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36280 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36281 * child nodes before loading.
36283 clearOnLoad : true,
36286 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36287 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36288 * Grid query { data : [ .....] }
36293 * @cfg {String} queryParam (optional)
36294 * Name of the query as it will be passed on the querystring (defaults to 'node')
36295 * eg. the request will be ?node=[id]
36302 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36303 * This is called automatically when a node is expanded, but may be used to reload
36304 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36305 * @param {Roo.tree.TreeNode} node
36306 * @param {Function} callback
36308 load : function(node, callback){
36309 if(this.clearOnLoad){
36310 while(node.firstChild){
36311 node.removeChild(node.firstChild);
36314 if(node.attributes.children){ // preloaded json children
36315 var cs = node.attributes.children;
36316 for(var i = 0, len = cs.length; i < len; i++){
36317 node.appendChild(this.createNode(cs[i]));
36319 if(typeof callback == "function"){
36322 }else if(this.dataUrl){
36323 this.requestData(node, callback);
36327 getParams: function(node){
36328 var buf = [], bp = this.baseParams;
36329 for(var key in bp){
36330 if(typeof bp[key] != "function"){
36331 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36334 var n = this.queryParam === false ? 'node' : this.queryParam;
36335 buf.push(n + "=", encodeURIComponent(node.id));
36336 return buf.join("");
36339 requestData : function(node, callback){
36340 if(this.fireEvent("beforeload", this, node, callback) !== false){
36341 this.transId = Roo.Ajax.request({
36342 method:this.requestMethod,
36343 url: this.dataUrl||this.url,
36344 success: this.handleResponse,
36345 failure: this.handleFailure,
36347 argument: {callback: callback, node: node},
36348 params: this.getParams(node)
36351 // if the load is cancelled, make sure we notify
36352 // the node that we are done
36353 if(typeof callback == "function"){
36359 isLoading : function(){
36360 return this.transId ? true : false;
36363 abort : function(){
36364 if(this.isLoading()){
36365 Roo.Ajax.abort(this.transId);
36370 createNode : function(attr)
36372 // apply baseAttrs, nice idea Corey!
36373 if(this.baseAttrs){
36374 Roo.applyIf(attr, this.baseAttrs);
36376 if(this.applyLoader !== false){
36377 attr.loader = this;
36379 // uiProvider = depreciated..
36381 if(typeof(attr.uiProvider) == 'string'){
36382 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36383 /** eval:var:attr */ eval(attr.uiProvider);
36385 if(typeof(this.uiProviders['default']) != 'undefined') {
36386 attr.uiProvider = this.uiProviders['default'];
36389 this.fireEvent('create', this, attr);
36391 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36393 new Roo.tree.TreeNode(attr) :
36394 new Roo.tree.AsyncTreeNode(attr));
36397 processResponse : function(response, node, callback)
36399 var json = response.responseText;
36402 var o = Roo.decode(json);
36404 if (this.root === false && typeof(o.success) != undefined) {
36405 this.root = 'data'; // the default behaviour for list like data..
36408 if (this.root !== false && !o.success) {
36409 // it's a failure condition.
36410 var a = response.argument;
36411 this.fireEvent("loadexception", this, a.node, response);
36412 Roo.log("Load failed - should have a handler really");
36418 if (this.root !== false) {
36422 for(var i = 0, len = o.length; i < len; i++){
36423 var n = this.createNode(o[i]);
36425 node.appendChild(n);
36428 if(typeof callback == "function"){
36429 callback(this, node);
36432 this.handleFailure(response);
36436 handleResponse : function(response){
36437 this.transId = false;
36438 var a = response.argument;
36439 this.processResponse(response, a.node, a.callback);
36440 this.fireEvent("load", this, a.node, response);
36443 handleFailure : function(response)
36445 // should handle failure better..
36446 this.transId = false;
36447 var a = response.argument;
36448 this.fireEvent("loadexception", this, a.node, response);
36449 if(typeof a.callback == "function"){
36450 a.callback(this, a.node);
36455 * Ext JS Library 1.1.1
36456 * Copyright(c) 2006-2007, Ext JS, LLC.
36458 * Originally Released Under LGPL - original licence link has changed is not relivant.
36461 * <script type="text/javascript">
36465 * @class Roo.tree.TreeFilter
36466 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36467 * @param {TreePanel} tree
36468 * @param {Object} config (optional)
36470 Roo.tree.TreeFilter = function(tree, config){
36472 this.filtered = {};
36473 Roo.apply(this, config);
36476 Roo.tree.TreeFilter.prototype = {
36483 * Filter the data by a specific attribute.
36484 * @param {String/RegExp} value Either string that the attribute value
36485 * should start with or a RegExp to test against the attribute
36486 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36487 * @param {TreeNode} startNode (optional) The node to start the filter at.
36489 filter : function(value, attr, startNode){
36490 attr = attr || "text";
36492 if(typeof value == "string"){
36493 var vlen = value.length;
36494 // auto clear empty filter
36495 if(vlen == 0 && this.clearBlank){
36499 value = value.toLowerCase();
36501 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36503 }else if(value.exec){ // regex?
36505 return value.test(n.attributes[attr]);
36508 throw 'Illegal filter type, must be string or regex';
36510 this.filterBy(f, null, startNode);
36514 * Filter by a function. The passed function will be called with each
36515 * node in the tree (or from the startNode). If the function returns true, the node is kept
36516 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36517 * @param {Function} fn The filter function
36518 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36520 filterBy : function(fn, scope, startNode){
36521 startNode = startNode || this.tree.root;
36522 if(this.autoClear){
36525 var af = this.filtered, rv = this.reverse;
36526 var f = function(n){
36527 if(n == startNode){
36533 var m = fn.call(scope || n, n);
36541 startNode.cascade(f);
36544 if(typeof id != "function"){
36546 if(n && n.parentNode){
36547 n.parentNode.removeChild(n);
36555 * Clears the current filter. Note: with the "remove" option
36556 * set a filter cannot be cleared.
36558 clear : function(){
36560 var af = this.filtered;
36562 if(typeof id != "function"){
36569 this.filtered = {};
36574 * Ext JS Library 1.1.1
36575 * Copyright(c) 2006-2007, Ext JS, LLC.
36577 * Originally Released Under LGPL - original licence link has changed is not relivant.
36580 * <script type="text/javascript">
36585 * @class Roo.tree.TreeSorter
36586 * Provides sorting of nodes in a TreePanel
36588 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36589 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36590 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36591 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36592 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36593 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36595 * @param {TreePanel} tree
36596 * @param {Object} config
36598 Roo.tree.TreeSorter = function(tree, config){
36599 Roo.apply(this, config);
36600 tree.on("beforechildrenrendered", this.doSort, this);
36601 tree.on("append", this.updateSort, this);
36602 tree.on("insert", this.updateSort, this);
36604 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36605 var p = this.property || "text";
36606 var sortType = this.sortType;
36607 var fs = this.folderSort;
36608 var cs = this.caseSensitive === true;
36609 var leafAttr = this.leafAttr || 'leaf';
36611 this.sortFn = function(n1, n2){
36613 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36616 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36620 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36621 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36623 return dsc ? +1 : -1;
36625 return dsc ? -1 : +1;
36632 Roo.tree.TreeSorter.prototype = {
36633 doSort : function(node){
36634 node.sort(this.sortFn);
36637 compareNodes : function(n1, n2){
36638 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36641 updateSort : function(tree, node){
36642 if(node.childrenRendered){
36643 this.doSort.defer(1, this, [node]);
36648 * Ext JS Library 1.1.1
36649 * Copyright(c) 2006-2007, Ext JS, LLC.
36651 * Originally Released Under LGPL - original licence link has changed is not relivant.
36654 * <script type="text/javascript">
36657 if(Roo.dd.DropZone){
36659 Roo.tree.TreeDropZone = function(tree, config){
36660 this.allowParentInsert = false;
36661 this.allowContainerDrop = false;
36662 this.appendOnly = false;
36663 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36665 this.lastInsertClass = "x-tree-no-status";
36666 this.dragOverData = {};
36669 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36670 ddGroup : "TreeDD",
36673 expandDelay : 1000,
36675 expandNode : function(node){
36676 if(node.hasChildNodes() && !node.isExpanded()){
36677 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36681 queueExpand : function(node){
36682 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36685 cancelExpand : function(){
36686 if(this.expandProcId){
36687 clearTimeout(this.expandProcId);
36688 this.expandProcId = false;
36692 isValidDropPoint : function(n, pt, dd, e, data){
36693 if(!n || !data){ return false; }
36694 var targetNode = n.node;
36695 var dropNode = data.node;
36696 // default drop rules
36697 if(!(targetNode && targetNode.isTarget && pt)){
36700 if(pt == "append" && targetNode.allowChildren === false){
36703 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36706 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36709 // reuse the object
36710 var overEvent = this.dragOverData;
36711 overEvent.tree = this.tree;
36712 overEvent.target = targetNode;
36713 overEvent.data = data;
36714 overEvent.point = pt;
36715 overEvent.source = dd;
36716 overEvent.rawEvent = e;
36717 overEvent.dropNode = dropNode;
36718 overEvent.cancel = false;
36719 var result = this.tree.fireEvent("nodedragover", overEvent);
36720 return overEvent.cancel === false && result !== false;
36723 getDropPoint : function(e, n, dd)
36727 return tn.allowChildren !== false ? "append" : false; // always append for root
36729 var dragEl = n.ddel;
36730 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36731 var y = Roo.lib.Event.getPageY(e);
36732 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36734 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36735 var noAppend = tn.allowChildren === false;
36736 if(this.appendOnly || tn.parentNode.allowChildren === false){
36737 return noAppend ? false : "append";
36739 var noBelow = false;
36740 if(!this.allowParentInsert){
36741 noBelow = tn.hasChildNodes() && tn.isExpanded();
36743 var q = (b - t) / (noAppend ? 2 : 3);
36744 if(y >= t && y < (t + q)){
36746 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36753 onNodeEnter : function(n, dd, e, data)
36755 this.cancelExpand();
36758 onNodeOver : function(n, dd, e, data)
36761 var pt = this.getDropPoint(e, n, dd);
36764 // auto node expand check
36765 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36766 this.queueExpand(node);
36767 }else if(pt != "append"){
36768 this.cancelExpand();
36771 // set the insert point style on the target node
36772 var returnCls = this.dropNotAllowed;
36773 if(this.isValidDropPoint(n, pt, dd, e, data)){
36778 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36779 cls = "x-tree-drag-insert-above";
36780 }else if(pt == "below"){
36781 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36782 cls = "x-tree-drag-insert-below";
36784 returnCls = "x-tree-drop-ok-append";
36785 cls = "x-tree-drag-append";
36787 if(this.lastInsertClass != cls){
36788 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36789 this.lastInsertClass = cls;
36796 onNodeOut : function(n, dd, e, data){
36798 this.cancelExpand();
36799 this.removeDropIndicators(n);
36802 onNodeDrop : function(n, dd, e, data){
36803 var point = this.getDropPoint(e, n, dd);
36804 var targetNode = n.node;
36805 targetNode.ui.startDrop();
36806 if(!this.isValidDropPoint(n, point, dd, e, data)){
36807 targetNode.ui.endDrop();
36810 // first try to find the drop node
36811 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36814 target: targetNode,
36819 dropNode: dropNode,
36822 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36823 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36824 targetNode.ui.endDrop();
36827 // allow target changing
36828 targetNode = dropEvent.target;
36829 if(point == "append" && !targetNode.isExpanded()){
36830 targetNode.expand(false, null, function(){
36831 this.completeDrop(dropEvent);
36832 }.createDelegate(this));
36834 this.completeDrop(dropEvent);
36839 completeDrop : function(de){
36840 var ns = de.dropNode, p = de.point, t = de.target;
36841 if(!(ns instanceof Array)){
36845 for(var i = 0, len = ns.length; i < len; i++){
36848 t.parentNode.insertBefore(n, t);
36849 }else if(p == "below"){
36850 t.parentNode.insertBefore(n, t.nextSibling);
36856 if(this.tree.hlDrop){
36860 this.tree.fireEvent("nodedrop", de);
36863 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36864 if(this.tree.hlDrop){
36865 dropNode.ui.focus();
36866 dropNode.ui.highlight();
36868 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36871 getTree : function(){
36875 removeDropIndicators : function(n){
36878 Roo.fly(el).removeClass([
36879 "x-tree-drag-insert-above",
36880 "x-tree-drag-insert-below",
36881 "x-tree-drag-append"]);
36882 this.lastInsertClass = "_noclass";
36886 beforeDragDrop : function(target, e, id){
36887 this.cancelExpand();
36891 afterRepair : function(data){
36892 if(data && Roo.enableFx){
36893 data.node.ui.highlight();
36903 * Ext JS Library 1.1.1
36904 * Copyright(c) 2006-2007, Ext JS, LLC.
36906 * Originally Released Under LGPL - original licence link has changed is not relivant.
36909 * <script type="text/javascript">
36913 if(Roo.dd.DragZone){
36914 Roo.tree.TreeDragZone = function(tree, config){
36915 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36919 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36920 ddGroup : "TreeDD",
36922 onBeforeDrag : function(data, e){
36924 return n && n.draggable && !n.disabled;
36928 onInitDrag : function(e){
36929 var data = this.dragData;
36930 this.tree.getSelectionModel().select(data.node);
36931 this.proxy.update("");
36932 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36933 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36936 getRepairXY : function(e, data){
36937 return data.node.ui.getDDRepairXY();
36940 onEndDrag : function(data, e){
36941 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36946 onValidDrop : function(dd, e, id){
36947 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36951 beforeInvalidDrop : function(e, id){
36952 // this scrolls the original position back into view
36953 var sm = this.tree.getSelectionModel();
36954 sm.clearSelections();
36955 sm.select(this.dragData.node);
36960 * Ext JS Library 1.1.1
36961 * Copyright(c) 2006-2007, Ext JS, LLC.
36963 * Originally Released Under LGPL - original licence link has changed is not relivant.
36966 * <script type="text/javascript">
36969 * @class Roo.tree.TreeEditor
36970 * @extends Roo.Editor
36971 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36972 * as the editor field.
36974 * @param {Object} config (used to be the tree panel.)
36975 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36977 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36978 * @cfg {Roo.form.TextField|Object} field The field configuration
36982 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36985 if (oldconfig) { // old style..
36986 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36989 tree = config.tree;
36990 config.field = config.field || {};
36991 config.field.xtype = 'TextField';
36992 field = Roo.factory(config.field, Roo.form);
36994 config = config || {};
36999 * @event beforenodeedit
37000 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37001 * false from the handler of this event.
37002 * @param {Editor} this
37003 * @param {Roo.tree.Node} node
37005 "beforenodeedit" : true
37009 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37013 tree.on('beforeclick', this.beforeNodeClick, this);
37014 tree.getTreeEl().on('mousedown', this.hide, this);
37015 this.on('complete', this.updateNode, this);
37016 this.on('beforestartedit', this.fitToTree, this);
37017 this.on('startedit', this.bindScroll, this, {delay:10});
37018 this.on('specialkey', this.onSpecialKey, this);
37021 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
37023 * @cfg {String} alignment
37024 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37030 * @cfg {Boolean} hideEl
37031 * True to hide the bound element while the editor is displayed (defaults to false)
37035 * @cfg {String} cls
37036 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37038 cls: "x-small-editor x-tree-editor",
37040 * @cfg {Boolean} shim
37041 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37047 * @cfg {Number} maxWidth
37048 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37049 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37050 * scroll and client offsets into account prior to each edit.
37057 fitToTree : function(ed, el){
37058 var td = this.tree.getTreeEl().dom, nd = el.dom;
37059 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37060 td.scrollLeft = nd.offsetLeft;
37064 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37065 this.setSize(w, '');
37067 return this.fireEvent('beforenodeedit', this, this.editNode);
37072 triggerEdit : function(node){
37073 this.completeEdit();
37074 this.editNode = node;
37075 this.startEdit(node.ui.textNode, node.text);
37079 bindScroll : function(){
37080 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37084 beforeNodeClick : function(node, e){
37085 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37086 this.lastClick = new Date();
37087 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37089 this.triggerEdit(node);
37096 updateNode : function(ed, value){
37097 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37098 this.editNode.setText(value);
37102 onHide : function(){
37103 Roo.tree.TreeEditor.superclass.onHide.call(this);
37105 this.editNode.ui.focus();
37110 onSpecialKey : function(field, e){
37111 var k = e.getKey();
37115 }else if(k == e.ENTER && !e.hasModifier()){
37117 this.completeEdit();
37120 });//<Script type="text/javascript">
37123 * Ext JS Library 1.1.1
37124 * Copyright(c) 2006-2007, Ext JS, LLC.
37126 * Originally Released Under LGPL - original licence link has changed is not relivant.
37129 * <script type="text/javascript">
37133 * Not documented??? - probably should be...
37136 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37137 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37139 renderElements : function(n, a, targetNode, bulkRender){
37140 //consel.log("renderElements?");
37141 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37143 var t = n.getOwnerTree();
37144 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37146 var cols = t.columns;
37147 var bw = t.borderWidth;
37149 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37150 var cb = typeof a.checked == "boolean";
37151 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37152 var colcls = 'x-t-' + tid + '-c0';
37154 '<li class="x-tree-node">',
37157 '<div class="x-tree-node-el ', a.cls,'">',
37159 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37162 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37163 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37164 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37165 (a.icon ? ' x-tree-node-inline-icon' : ''),
37166 (a.iconCls ? ' '+a.iconCls : ''),
37167 '" unselectable="on" />',
37168 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37169 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37171 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37172 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37173 '<span unselectable="on" qtip="' + tx + '">',
37177 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37178 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37180 for(var i = 1, len = cols.length; i < len; i++){
37182 colcls = 'x-t-' + tid + '-c' +i;
37183 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37184 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37185 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37191 '<div class="x-clear"></div></div>',
37192 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37195 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37196 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37197 n.nextSibling.ui.getEl(), buf.join(""));
37199 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37201 var el = this.wrap.firstChild;
37203 this.elNode = el.firstChild;
37204 this.ranchor = el.childNodes[1];
37205 this.ctNode = this.wrap.childNodes[1];
37206 var cs = el.firstChild.childNodes;
37207 this.indentNode = cs[0];
37208 this.ecNode = cs[1];
37209 this.iconNode = cs[2];
37212 this.checkbox = cs[3];
37215 this.anchor = cs[index];
37217 this.textNode = cs[index].firstChild;
37219 //el.on("click", this.onClick, this);
37220 //el.on("dblclick", this.onDblClick, this);
37223 // console.log(this);
37225 initEvents : function(){
37226 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37229 var a = this.ranchor;
37231 var el = Roo.get(a);
37233 if(Roo.isOpera){ // opera render bug ignores the CSS
37234 el.setStyle("text-decoration", "none");
37237 el.on("click", this.onClick, this);
37238 el.on("dblclick", this.onDblClick, this);
37239 el.on("contextmenu", this.onContextMenu, this);
37243 /*onSelectedChange : function(state){
37246 this.addClass("x-tree-selected");
37249 this.removeClass("x-tree-selected");
37252 addClass : function(cls){
37254 Roo.fly(this.elRow).addClass(cls);
37260 removeClass : function(cls){
37262 Roo.fly(this.elRow).removeClass(cls);
37268 });//<Script type="text/javascript">
37272 * Ext JS Library 1.1.1
37273 * Copyright(c) 2006-2007, Ext JS, LLC.
37275 * Originally Released Under LGPL - original licence link has changed is not relivant.
37278 * <script type="text/javascript">
37283 * @class Roo.tree.ColumnTree
37284 * @extends Roo.data.TreePanel
37285 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37286 * @cfg {int} borderWidth compined right/left border allowance
37288 * @param {String/HTMLElement/Element} el The container element
37289 * @param {Object} config
37291 Roo.tree.ColumnTree = function(el, config)
37293 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37297 * Fire this event on a container when it resizes
37298 * @param {int} w Width
37299 * @param {int} h Height
37303 this.on('resize', this.onResize, this);
37306 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37310 borderWidth: Roo.isBorderBox ? 0 : 2,
37313 render : function(){
37314 // add the header.....
37316 Roo.tree.ColumnTree.superclass.render.apply(this);
37318 this.el.addClass('x-column-tree');
37320 this.headers = this.el.createChild(
37321 {cls:'x-tree-headers'},this.innerCt.dom);
37323 var cols = this.columns, c;
37324 var totalWidth = 0;
37326 var len = cols.length;
37327 for(var i = 0; i < len; i++){
37329 totalWidth += c.width;
37330 this.headEls.push(this.headers.createChild({
37331 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37333 cls:'x-tree-hd-text',
37336 style:'width:'+(c.width-this.borderWidth)+'px;'
37339 this.headers.createChild({cls:'x-clear'});
37340 // prevent floats from wrapping when clipped
37341 this.headers.setWidth(totalWidth);
37342 //this.innerCt.setWidth(totalWidth);
37343 this.innerCt.setStyle({ overflow: 'auto' });
37344 this.onResize(this.width, this.height);
37348 onResize : function(w,h)
37353 this.innerCt.setWidth(this.width);
37354 this.innerCt.setHeight(this.height-20);
37357 var cols = this.columns, c;
37358 var totalWidth = 0;
37360 var len = cols.length;
37361 for(var i = 0; i < len; i++){
37363 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37364 // it's the expander..
37365 expEl = this.headEls[i];
37368 totalWidth += c.width;
37372 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37374 this.headers.setWidth(w-20);
37383 * Ext JS Library 1.1.1
37384 * Copyright(c) 2006-2007, Ext JS, LLC.
37386 * Originally Released Under LGPL - original licence link has changed is not relivant.
37389 * <script type="text/javascript">
37393 * @class Roo.menu.Menu
37394 * @extends Roo.util.Observable
37395 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37396 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37398 * Creates a new Menu
37399 * @param {Object} config Configuration options
37401 Roo.menu.Menu = function(config){
37403 Roo.menu.Menu.superclass.constructor.call(this, config);
37405 this.id = this.id || Roo.id();
37408 * @event beforeshow
37409 * Fires before this menu is displayed
37410 * @param {Roo.menu.Menu} this
37414 * @event beforehide
37415 * Fires before this menu is hidden
37416 * @param {Roo.menu.Menu} this
37421 * Fires after this menu is displayed
37422 * @param {Roo.menu.Menu} this
37427 * Fires after this menu is hidden
37428 * @param {Roo.menu.Menu} this
37433 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37434 * @param {Roo.menu.Menu} this
37435 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37436 * @param {Roo.EventObject} e
37441 * Fires when the mouse is hovering over this menu
37442 * @param {Roo.menu.Menu} this
37443 * @param {Roo.EventObject} e
37444 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37449 * Fires when the mouse exits this menu
37450 * @param {Roo.menu.Menu} this
37451 * @param {Roo.EventObject} e
37452 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37457 * Fires when a menu item contained in this menu is clicked
37458 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37459 * @param {Roo.EventObject} e
37463 if (this.registerMenu) {
37464 Roo.menu.MenuMgr.register(this);
37467 var mis = this.items;
37468 this.items = new Roo.util.MixedCollection();
37470 this.add.apply(this, mis);
37474 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37476 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37480 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37481 * for bottom-right shadow (defaults to "sides")
37485 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37486 * this menu (defaults to "tl-tr?")
37488 subMenuAlign : "tl-tr?",
37490 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37491 * relative to its element of origin (defaults to "tl-bl?")
37493 defaultAlign : "tl-bl?",
37495 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37497 allowOtherMenus : false,
37499 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37501 registerMenu : true,
37506 render : function(){
37510 var el = this.el = new Roo.Layer({
37512 shadow:this.shadow,
37514 parentEl: this.parentEl || document.body,
37518 this.keyNav = new Roo.menu.MenuNav(this);
37521 el.addClass("x-menu-plain");
37524 el.addClass(this.cls);
37526 // generic focus element
37527 this.focusEl = el.createChild({
37528 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37530 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37531 //disabling touch- as it's causing issues ..
37532 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37533 ul.on('click' , this.onClick, this);
37536 ul.on("mouseover", this.onMouseOver, this);
37537 ul.on("mouseout", this.onMouseOut, this);
37538 this.items.each(function(item){
37543 var li = document.createElement("li");
37544 li.className = "x-menu-list-item";
37545 ul.dom.appendChild(li);
37546 item.render(li, this);
37553 autoWidth : function(){
37554 var el = this.el, ul = this.ul;
37558 var w = this.width;
37561 }else if(Roo.isIE){
37562 el.setWidth(this.minWidth);
37563 var t = el.dom.offsetWidth; // force recalc
37564 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37569 delayAutoWidth : function(){
37572 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37574 this.awTask.delay(20);
37579 findTargetItem : function(e){
37580 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37581 if(t && t.menuItemId){
37582 return this.items.get(t.menuItemId);
37587 onClick : function(e){
37588 Roo.log("menu.onClick");
37589 var t = this.findTargetItem(e);
37594 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37595 if(t == this.activeItem && t.shouldDeactivate(e)){
37596 this.activeItem.deactivate();
37597 delete this.activeItem;
37601 this.setActiveItem(t, true);
37609 this.fireEvent("click", this, t, e);
37613 setActiveItem : function(item, autoExpand){
37614 if(item != this.activeItem){
37615 if(this.activeItem){
37616 this.activeItem.deactivate();
37618 this.activeItem = item;
37619 item.activate(autoExpand);
37620 }else if(autoExpand){
37626 tryActivate : function(start, step){
37627 var items = this.items;
37628 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37629 var item = items.get(i);
37630 if(!item.disabled && item.canActivate){
37631 this.setActiveItem(item, false);
37639 onMouseOver : function(e){
37641 if(t = this.findTargetItem(e)){
37642 if(t.canActivate && !t.disabled){
37643 this.setActiveItem(t, true);
37646 this.fireEvent("mouseover", this, e, t);
37650 onMouseOut : function(e){
37652 if(t = this.findTargetItem(e)){
37653 if(t == this.activeItem && t.shouldDeactivate(e)){
37654 this.activeItem.deactivate();
37655 delete this.activeItem;
37658 this.fireEvent("mouseout", this, e, t);
37662 * Read-only. Returns true if the menu is currently displayed, else false.
37665 isVisible : function(){
37666 return this.el && !this.hidden;
37670 * Displays this menu relative to another element
37671 * @param {String/HTMLElement/Roo.Element} element The element to align to
37672 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37673 * the element (defaults to this.defaultAlign)
37674 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37676 show : function(el, pos, parentMenu){
37677 this.parentMenu = parentMenu;
37681 this.fireEvent("beforeshow", this);
37682 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37686 * Displays this menu at a specific xy position
37687 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37688 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37690 showAt : function(xy, parentMenu, /* private: */_e){
37691 this.parentMenu = parentMenu;
37696 this.fireEvent("beforeshow", this);
37697 xy = this.el.adjustForConstraints(xy);
37701 this.hidden = false;
37703 this.fireEvent("show", this);
37706 focus : function(){
37708 this.doFocus.defer(50, this);
37712 doFocus : function(){
37714 this.focusEl.focus();
37719 * Hides this menu and optionally all parent menus
37720 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37722 hide : function(deep){
37723 if(this.el && this.isVisible()){
37724 this.fireEvent("beforehide", this);
37725 if(this.activeItem){
37726 this.activeItem.deactivate();
37727 this.activeItem = null;
37730 this.hidden = true;
37731 this.fireEvent("hide", this);
37733 if(deep === true && this.parentMenu){
37734 this.parentMenu.hide(true);
37739 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37740 * Any of the following are valid:
37742 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37743 * <li>An HTMLElement object which will be converted to a menu item</li>
37744 * <li>A menu item config object that will be created as a new menu item</li>
37745 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37746 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37751 var menu = new Roo.menu.Menu();
37753 // Create a menu item to add by reference
37754 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37756 // Add a bunch of items at once using different methods.
37757 // Only the last item added will be returned.
37758 var item = menu.add(
37759 menuItem, // add existing item by ref
37760 'Dynamic Item', // new TextItem
37761 '-', // new separator
37762 { text: 'Config Item' } // new item by config
37765 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37766 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37769 var a = arguments, l = a.length, item;
37770 for(var i = 0; i < l; i++){
37772 if ((typeof(el) == "object") && el.xtype && el.xns) {
37773 el = Roo.factory(el, Roo.menu);
37776 if(el.render){ // some kind of Item
37777 item = this.addItem(el);
37778 }else if(typeof el == "string"){ // string
37779 if(el == "separator" || el == "-"){
37780 item = this.addSeparator();
37782 item = this.addText(el);
37784 }else if(el.tagName || el.el){ // element
37785 item = this.addElement(el);
37786 }else if(typeof el == "object"){ // must be menu item config?
37787 item = this.addMenuItem(el);
37794 * Returns this menu's underlying {@link Roo.Element} object
37795 * @return {Roo.Element} The element
37797 getEl : function(){
37805 * Adds a separator bar to the menu
37806 * @return {Roo.menu.Item} The menu item that was added
37808 addSeparator : function(){
37809 return this.addItem(new Roo.menu.Separator());
37813 * Adds an {@link Roo.Element} object to the menu
37814 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37815 * @return {Roo.menu.Item} The menu item that was added
37817 addElement : function(el){
37818 return this.addItem(new Roo.menu.BaseItem(el));
37822 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37823 * @param {Roo.menu.Item} item The menu item to add
37824 * @return {Roo.menu.Item} The menu item that was added
37826 addItem : function(item){
37827 this.items.add(item);
37829 var li = document.createElement("li");
37830 li.className = "x-menu-list-item";
37831 this.ul.dom.appendChild(li);
37832 item.render(li, this);
37833 this.delayAutoWidth();
37839 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37840 * @param {Object} config A MenuItem config object
37841 * @return {Roo.menu.Item} The menu item that was added
37843 addMenuItem : function(config){
37844 if(!(config instanceof Roo.menu.Item)){
37845 if(typeof config.checked == "boolean"){ // must be check menu item config?
37846 config = new Roo.menu.CheckItem(config);
37848 config = new Roo.menu.Item(config);
37851 return this.addItem(config);
37855 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37856 * @param {String} text The text to display in the menu item
37857 * @return {Roo.menu.Item} The menu item that was added
37859 addText : function(text){
37860 return this.addItem(new Roo.menu.TextItem({ text : text }));
37864 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37865 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37866 * @param {Roo.menu.Item} item The menu item to add
37867 * @return {Roo.menu.Item} The menu item that was added
37869 insert : function(index, item){
37870 this.items.insert(index, item);
37872 var li = document.createElement("li");
37873 li.className = "x-menu-list-item";
37874 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37875 item.render(li, this);
37876 this.delayAutoWidth();
37882 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37883 * @param {Roo.menu.Item} item The menu item to remove
37885 remove : function(item){
37886 this.items.removeKey(item.id);
37891 * Removes and destroys all items in the menu
37893 removeAll : function(){
37895 while(f = this.items.first()){
37901 // MenuNav is a private utility class used internally by the Menu
37902 Roo.menu.MenuNav = function(menu){
37903 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37904 this.scope = this.menu = menu;
37907 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37908 doRelay : function(e, h){
37909 var k = e.getKey();
37910 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37911 this.menu.tryActivate(0, 1);
37914 return h.call(this.scope || this, e, this.menu);
37917 up : function(e, m){
37918 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37919 m.tryActivate(m.items.length-1, -1);
37923 down : function(e, m){
37924 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37925 m.tryActivate(0, 1);
37929 right : function(e, m){
37931 m.activeItem.expandMenu(true);
37935 left : function(e, m){
37937 if(m.parentMenu && m.parentMenu.activeItem){
37938 m.parentMenu.activeItem.activate();
37942 enter : function(e, m){
37944 e.stopPropagation();
37945 m.activeItem.onClick(e);
37946 m.fireEvent("click", this, m.activeItem);
37952 * Ext JS Library 1.1.1
37953 * Copyright(c) 2006-2007, Ext JS, LLC.
37955 * Originally Released Under LGPL - original licence link has changed is not relivant.
37958 * <script type="text/javascript">
37962 * @class Roo.menu.MenuMgr
37963 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37966 Roo.menu.MenuMgr = function(){
37967 var menus, active, groups = {}, attached = false, lastShow = new Date();
37969 // private - called when first menu is created
37972 active = new Roo.util.MixedCollection();
37973 Roo.get(document).addKeyListener(27, function(){
37974 if(active.length > 0){
37981 function hideAll(){
37982 if(active && active.length > 0){
37983 var c = active.clone();
37984 c.each(function(m){
37991 function onHide(m){
37993 if(active.length < 1){
37994 Roo.get(document).un("mousedown", onMouseDown);
38000 function onShow(m){
38001 var last = active.last();
38002 lastShow = new Date();
38005 Roo.get(document).on("mousedown", onMouseDown);
38009 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38010 m.parentMenu.activeChild = m;
38011 }else if(last && last.isVisible()){
38012 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
38017 function onBeforeHide(m){
38019 m.activeChild.hide();
38021 if(m.autoHideTimer){
38022 clearTimeout(m.autoHideTimer);
38023 delete m.autoHideTimer;
38028 function onBeforeShow(m){
38029 var pm = m.parentMenu;
38030 if(!pm && !m.allowOtherMenus){
38032 }else if(pm && pm.activeChild && active != m){
38033 pm.activeChild.hide();
38038 function onMouseDown(e){
38039 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38045 function onBeforeCheck(mi, state){
38047 var g = groups[mi.group];
38048 for(var i = 0, l = g.length; i < l; i++){
38050 g[i].setChecked(false);
38059 * Hides all menus that are currently visible
38061 hideAll : function(){
38066 register : function(menu){
38070 menus[menu.id] = menu;
38071 menu.on("beforehide", onBeforeHide);
38072 menu.on("hide", onHide);
38073 menu.on("beforeshow", onBeforeShow);
38074 menu.on("show", onShow);
38075 var g = menu.group;
38076 if(g && menu.events["checkchange"]){
38080 groups[g].push(menu);
38081 menu.on("checkchange", onCheck);
38086 * Returns a {@link Roo.menu.Menu} object
38087 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38088 * be used to generate and return a new Menu instance.
38090 get : function(menu){
38091 if(typeof menu == "string"){ // menu id
38092 return menus[menu];
38093 }else if(menu.events){ // menu instance
38095 }else if(typeof menu.length == 'number'){ // array of menu items?
38096 return new Roo.menu.Menu({items:menu});
38097 }else{ // otherwise, must be a config
38098 return new Roo.menu.Menu(menu);
38103 unregister : function(menu){
38104 delete menus[menu.id];
38105 menu.un("beforehide", onBeforeHide);
38106 menu.un("hide", onHide);
38107 menu.un("beforeshow", onBeforeShow);
38108 menu.un("show", onShow);
38109 var g = menu.group;
38110 if(g && menu.events["checkchange"]){
38111 groups[g].remove(menu);
38112 menu.un("checkchange", onCheck);
38117 registerCheckable : function(menuItem){
38118 var g = menuItem.group;
38123 groups[g].push(menuItem);
38124 menuItem.on("beforecheckchange", onBeforeCheck);
38129 unregisterCheckable : function(menuItem){
38130 var g = menuItem.group;
38132 groups[g].remove(menuItem);
38133 menuItem.un("beforecheckchange", onBeforeCheck);
38139 * Ext JS Library 1.1.1
38140 * Copyright(c) 2006-2007, Ext JS, LLC.
38142 * Originally Released Under LGPL - original licence link has changed is not relivant.
38145 * <script type="text/javascript">
38150 * @class Roo.menu.BaseItem
38151 * @extends Roo.Component
38152 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38153 * management and base configuration options shared by all menu components.
38155 * Creates a new BaseItem
38156 * @param {Object} config Configuration options
38158 Roo.menu.BaseItem = function(config){
38159 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38164 * Fires when this item is clicked
38165 * @param {Roo.menu.BaseItem} this
38166 * @param {Roo.EventObject} e
38171 * Fires when this item is activated
38172 * @param {Roo.menu.BaseItem} this
38176 * @event deactivate
38177 * Fires when this item is deactivated
38178 * @param {Roo.menu.BaseItem} this
38184 this.on("click", this.handler, this.scope, true);
38188 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38190 * @cfg {Function} handler
38191 * A function that will handle the click event of this menu item (defaults to undefined)
38194 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38196 canActivate : false,
38199 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38204 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38206 activeClass : "x-menu-item-active",
38208 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38210 hideOnClick : true,
38212 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38217 ctype: "Roo.menu.BaseItem",
38220 actionMode : "container",
38223 render : function(container, parentMenu){
38224 this.parentMenu = parentMenu;
38225 Roo.menu.BaseItem.superclass.render.call(this, container);
38226 this.container.menuItemId = this.id;
38230 onRender : function(container, position){
38231 this.el = Roo.get(this.el);
38232 container.dom.appendChild(this.el.dom);
38236 onClick : function(e){
38237 if(!this.disabled && this.fireEvent("click", this, e) !== false
38238 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38239 this.handleClick(e);
38246 activate : function(){
38250 var li = this.container;
38251 li.addClass(this.activeClass);
38252 this.region = li.getRegion().adjust(2, 2, -2, -2);
38253 this.fireEvent("activate", this);
38258 deactivate : function(){
38259 this.container.removeClass(this.activeClass);
38260 this.fireEvent("deactivate", this);
38264 shouldDeactivate : function(e){
38265 return !this.region || !this.region.contains(e.getPoint());
38269 handleClick : function(e){
38270 if(this.hideOnClick){
38271 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38276 expandMenu : function(autoActivate){
38281 hideMenu : function(){
38286 * Ext JS Library 1.1.1
38287 * Copyright(c) 2006-2007, Ext JS, LLC.
38289 * Originally Released Under LGPL - original licence link has changed is not relivant.
38292 * <script type="text/javascript">
38296 * @class Roo.menu.Adapter
38297 * @extends Roo.menu.BaseItem
38298 * 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.
38299 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38301 * Creates a new Adapter
38302 * @param {Object} config Configuration options
38304 Roo.menu.Adapter = function(component, config){
38305 Roo.menu.Adapter.superclass.constructor.call(this, config);
38306 this.component = component;
38308 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38310 canActivate : true,
38313 onRender : function(container, position){
38314 this.component.render(container);
38315 this.el = this.component.getEl();
38319 activate : function(){
38323 this.component.focus();
38324 this.fireEvent("activate", this);
38329 deactivate : function(){
38330 this.fireEvent("deactivate", this);
38334 disable : function(){
38335 this.component.disable();
38336 Roo.menu.Adapter.superclass.disable.call(this);
38340 enable : function(){
38341 this.component.enable();
38342 Roo.menu.Adapter.superclass.enable.call(this);
38346 * Ext JS Library 1.1.1
38347 * Copyright(c) 2006-2007, Ext JS, LLC.
38349 * Originally Released Under LGPL - original licence link has changed is not relivant.
38352 * <script type="text/javascript">
38356 * @class Roo.menu.TextItem
38357 * @extends Roo.menu.BaseItem
38358 * Adds a static text string to a menu, usually used as either a heading or group separator.
38359 * Note: old style constructor with text is still supported.
38362 * Creates a new TextItem
38363 * @param {Object} cfg Configuration
38365 Roo.menu.TextItem = function(cfg){
38366 if (typeof(cfg) == 'string') {
38369 Roo.apply(this,cfg);
38372 Roo.menu.TextItem.superclass.constructor.call(this);
38375 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38377 * @cfg {Boolean} text Text to show on item.
38382 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38384 hideOnClick : false,
38386 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38388 itemCls : "x-menu-text",
38391 onRender : function(){
38392 var s = document.createElement("span");
38393 s.className = this.itemCls;
38394 s.innerHTML = this.text;
38396 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38400 * Ext JS Library 1.1.1
38401 * Copyright(c) 2006-2007, Ext JS, LLC.
38403 * Originally Released Under LGPL - original licence link has changed is not relivant.
38406 * <script type="text/javascript">
38410 * @class Roo.menu.Separator
38411 * @extends Roo.menu.BaseItem
38412 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38413 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38415 * @param {Object} config Configuration options
38417 Roo.menu.Separator = function(config){
38418 Roo.menu.Separator.superclass.constructor.call(this, config);
38421 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38423 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38425 itemCls : "x-menu-sep",
38427 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38429 hideOnClick : false,
38432 onRender : function(li){
38433 var s = document.createElement("span");
38434 s.className = this.itemCls;
38435 s.innerHTML = " ";
38437 li.addClass("x-menu-sep-li");
38438 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38442 * Ext JS Library 1.1.1
38443 * Copyright(c) 2006-2007, Ext JS, LLC.
38445 * Originally Released Under LGPL - original licence link has changed is not relivant.
38448 * <script type="text/javascript">
38451 * @class Roo.menu.Item
38452 * @extends Roo.menu.BaseItem
38453 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38454 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38455 * activation and click handling.
38457 * Creates a new Item
38458 * @param {Object} config Configuration options
38460 Roo.menu.Item = function(config){
38461 Roo.menu.Item.superclass.constructor.call(this, config);
38463 this.menu = Roo.menu.MenuMgr.get(this.menu);
38466 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38469 * @cfg {String} text
38470 * The text to show on the menu item.
38474 * @cfg {String} HTML to render in menu
38475 * The text to show on the menu item (HTML version).
38479 * @cfg {String} icon
38480 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38484 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38486 itemCls : "x-menu-item",
38488 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38490 canActivate : true,
38492 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38495 // doc'd in BaseItem
38499 ctype: "Roo.menu.Item",
38502 onRender : function(container, position){
38503 var el = document.createElement("a");
38504 el.hideFocus = true;
38505 el.unselectable = "on";
38506 el.href = this.href || "#";
38507 if(this.hrefTarget){
38508 el.target = this.hrefTarget;
38510 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38512 var html = this.html.length ? this.html : String.format('{0}',this.text);
38514 el.innerHTML = String.format(
38515 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38516 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38518 Roo.menu.Item.superclass.onRender.call(this, container, position);
38522 * Sets the text to display in this menu item
38523 * @param {String} text The text to display
38524 * @param {Boolean} isHTML true to indicate text is pure html.
38526 setText : function(text, isHTML){
38534 var html = this.html.length ? this.html : String.format('{0}',this.text);
38536 this.el.update(String.format(
38537 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38538 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38539 this.parentMenu.autoWidth();
38544 handleClick : function(e){
38545 if(!this.href){ // if no link defined, stop the event automatically
38548 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38552 activate : function(autoExpand){
38553 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38563 shouldDeactivate : function(e){
38564 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38565 if(this.menu && this.menu.isVisible()){
38566 return !this.menu.getEl().getRegion().contains(e.getPoint());
38574 deactivate : function(){
38575 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38580 expandMenu : function(autoActivate){
38581 if(!this.disabled && this.menu){
38582 clearTimeout(this.hideTimer);
38583 delete this.hideTimer;
38584 if(!this.menu.isVisible() && !this.showTimer){
38585 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38586 }else if (this.menu.isVisible() && autoActivate){
38587 this.menu.tryActivate(0, 1);
38593 deferExpand : function(autoActivate){
38594 delete this.showTimer;
38595 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38597 this.menu.tryActivate(0, 1);
38602 hideMenu : function(){
38603 clearTimeout(this.showTimer);
38604 delete this.showTimer;
38605 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38606 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38611 deferHide : function(){
38612 delete this.hideTimer;
38617 * Ext JS Library 1.1.1
38618 * Copyright(c) 2006-2007, Ext JS, LLC.
38620 * Originally Released Under LGPL - original licence link has changed is not relivant.
38623 * <script type="text/javascript">
38627 * @class Roo.menu.CheckItem
38628 * @extends Roo.menu.Item
38629 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38631 * Creates a new CheckItem
38632 * @param {Object} config Configuration options
38634 Roo.menu.CheckItem = function(config){
38635 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38638 * @event beforecheckchange
38639 * Fires before the checked value is set, providing an opportunity to cancel if needed
38640 * @param {Roo.menu.CheckItem} this
38641 * @param {Boolean} checked The new checked value that will be set
38643 "beforecheckchange" : true,
38645 * @event checkchange
38646 * Fires after the checked value has been set
38647 * @param {Roo.menu.CheckItem} this
38648 * @param {Boolean} checked The checked value that was set
38650 "checkchange" : true
38652 if(this.checkHandler){
38653 this.on('checkchange', this.checkHandler, this.scope);
38656 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38658 * @cfg {String} group
38659 * All check items with the same group name will automatically be grouped into a single-select
38660 * radio button group (defaults to '')
38663 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38665 itemCls : "x-menu-item x-menu-check-item",
38667 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38669 groupClass : "x-menu-group-item",
38672 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38673 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38674 * initialized with checked = true will be rendered as checked.
38679 ctype: "Roo.menu.CheckItem",
38682 onRender : function(c){
38683 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38685 this.el.addClass(this.groupClass);
38687 Roo.menu.MenuMgr.registerCheckable(this);
38689 this.checked = false;
38690 this.setChecked(true, true);
38695 destroy : function(){
38697 Roo.menu.MenuMgr.unregisterCheckable(this);
38699 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38703 * Set the checked state of this item
38704 * @param {Boolean} checked The new checked value
38705 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38707 setChecked : function(state, suppressEvent){
38708 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38709 if(this.container){
38710 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38712 this.checked = state;
38713 if(suppressEvent !== true){
38714 this.fireEvent("checkchange", this, state);
38720 handleClick : function(e){
38721 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38722 this.setChecked(!this.checked);
38724 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38728 * Ext JS Library 1.1.1
38729 * Copyright(c) 2006-2007, Ext JS, LLC.
38731 * Originally Released Under LGPL - original licence link has changed is not relivant.
38734 * <script type="text/javascript">
38738 * @class Roo.menu.DateItem
38739 * @extends Roo.menu.Adapter
38740 * A menu item that wraps the {@link Roo.DatPicker} component.
38742 * Creates a new DateItem
38743 * @param {Object} config Configuration options
38745 Roo.menu.DateItem = function(config){
38746 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38747 /** The Roo.DatePicker object @type Roo.DatePicker */
38748 this.picker = this.component;
38749 this.addEvents({select: true});
38751 this.picker.on("render", function(picker){
38752 picker.getEl().swallowEvent("click");
38753 picker.container.addClass("x-menu-date-item");
38756 this.picker.on("select", this.onSelect, this);
38759 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38761 onSelect : function(picker, date){
38762 this.fireEvent("select", this, date, picker);
38763 Roo.menu.DateItem.superclass.handleClick.call(this);
38767 * Ext JS Library 1.1.1
38768 * Copyright(c) 2006-2007, Ext JS, LLC.
38770 * Originally Released Under LGPL - original licence link has changed is not relivant.
38773 * <script type="text/javascript">
38777 * @class Roo.menu.ColorItem
38778 * @extends Roo.menu.Adapter
38779 * A menu item that wraps the {@link Roo.ColorPalette} component.
38781 * Creates a new ColorItem
38782 * @param {Object} config Configuration options
38784 Roo.menu.ColorItem = function(config){
38785 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38786 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38787 this.palette = this.component;
38788 this.relayEvents(this.palette, ["select"]);
38789 if(this.selectHandler){
38790 this.on('select', this.selectHandler, this.scope);
38793 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38795 * Ext JS Library 1.1.1
38796 * Copyright(c) 2006-2007, Ext JS, LLC.
38798 * Originally Released Under LGPL - original licence link has changed is not relivant.
38801 * <script type="text/javascript">
38806 * @class Roo.menu.DateMenu
38807 * @extends Roo.menu.Menu
38808 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38810 * Creates a new DateMenu
38811 * @param {Object} config Configuration options
38813 Roo.menu.DateMenu = function(config){
38814 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38816 var di = new Roo.menu.DateItem(config);
38819 * The {@link Roo.DatePicker} instance for this DateMenu
38822 this.picker = di.picker;
38825 * @param {DatePicker} picker
38826 * @param {Date} date
38828 this.relayEvents(di, ["select"]);
38829 this.on('beforeshow', function(){
38831 this.picker.hideMonthPicker(false);
38835 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38839 * Ext JS Library 1.1.1
38840 * Copyright(c) 2006-2007, Ext JS, LLC.
38842 * Originally Released Under LGPL - original licence link has changed is not relivant.
38845 * <script type="text/javascript">
38850 * @class Roo.menu.ColorMenu
38851 * @extends Roo.menu.Menu
38852 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38854 * Creates a new ColorMenu
38855 * @param {Object} config Configuration options
38857 Roo.menu.ColorMenu = function(config){
38858 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38860 var ci = new Roo.menu.ColorItem(config);
38863 * The {@link Roo.ColorPalette} instance for this ColorMenu
38864 * @type ColorPalette
38866 this.palette = ci.palette;
38869 * @param {ColorPalette} palette
38870 * @param {String} color
38872 this.relayEvents(ci, ["select"]);
38874 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38876 * Ext JS Library 1.1.1
38877 * Copyright(c) 2006-2007, Ext JS, LLC.
38879 * Originally Released Under LGPL - original licence link has changed is not relivant.
38882 * <script type="text/javascript">
38886 * @class Roo.form.TextItem
38887 * @extends Roo.BoxComponent
38888 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38890 * Creates a new TextItem
38891 * @param {Object} config Configuration options
38893 Roo.form.TextItem = function(config){
38894 Roo.form.TextItem.superclass.constructor.call(this, config);
38897 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
38900 * @cfg {String} tag the tag for this item (default div)
38904 * @cfg {String} html the content for this item
38908 getAutoCreate : function()
38921 onRender : function(ct, position)
38923 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
38926 var cfg = this.getAutoCreate();
38928 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38930 if (!cfg.name.length) {
38933 this.el = ct.createChild(cfg, position);
38938 * @param {String} html update the Contents of the element.
38940 setHTML : function(html)
38942 this.fieldEl.dom.innerHTML = html;
38947 * Ext JS Library 1.1.1
38948 * Copyright(c) 2006-2007, Ext JS, LLC.
38950 * Originally Released Under LGPL - original licence link has changed is not relivant.
38953 * <script type="text/javascript">
38957 * @class Roo.form.Field
38958 * @extends Roo.BoxComponent
38959 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38961 * Creates a new Field
38962 * @param {Object} config Configuration options
38964 Roo.form.Field = function(config){
38965 Roo.form.Field.superclass.constructor.call(this, config);
38968 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38970 * @cfg {String} fieldLabel Label to use when rendering a form.
38973 * @cfg {String} qtip Mouse over tip
38977 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38979 invalidClass : "x-form-invalid",
38981 * @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")
38983 invalidText : "The value in this field is invalid",
38985 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38987 focusClass : "x-form-focus",
38989 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38990 automatic validation (defaults to "keyup").
38992 validationEvent : "keyup",
38994 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38996 validateOnBlur : true,
38998 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39000 validationDelay : 250,
39002 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39003 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39005 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39007 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39009 fieldClass : "x-form-field",
39011 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
39014 ----------- ----------------------------------------------------------------------
39015 qtip Display a quick tip when the user hovers over the field
39016 title Display a default browser title attribute popup
39017 under Add a block div beneath the field containing the error text
39018 side Add an error icon to the right of the field with a popup on hover
39019 [element id] Add the error text directly to the innerHTML of the specified element
39022 msgTarget : 'qtip',
39024 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39029 * @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.
39034 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39039 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39041 inputType : undefined,
39044 * @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).
39046 tabIndex : undefined,
39049 isFormField : true,
39054 * @property {Roo.Element} fieldEl
39055 * Element Containing the rendered Field (with label etc.)
39058 * @cfg {Mixed} value A value to initialize this field with.
39063 * @cfg {String} name The field's HTML name attribute.
39066 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39069 loadedValue : false,
39073 initComponent : function(){
39074 Roo.form.Field.superclass.initComponent.call(this);
39078 * Fires when this field receives input focus.
39079 * @param {Roo.form.Field} this
39084 * Fires when this field loses input focus.
39085 * @param {Roo.form.Field} this
39089 * @event specialkey
39090 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39091 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39092 * @param {Roo.form.Field} this
39093 * @param {Roo.EventObject} e The event object
39098 * Fires just before the field blurs if the field value has changed.
39099 * @param {Roo.form.Field} this
39100 * @param {Mixed} newValue The new value
39101 * @param {Mixed} oldValue The original value
39106 * Fires after the field has been marked as invalid.
39107 * @param {Roo.form.Field} this
39108 * @param {String} msg The validation message
39113 * Fires after the field has been validated with no errors.
39114 * @param {Roo.form.Field} this
39119 * Fires after the key up
39120 * @param {Roo.form.Field} this
39121 * @param {Roo.EventObject} e The event Object
39128 * Returns the name attribute of the field if available
39129 * @return {String} name The field name
39131 getName: function(){
39132 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39136 onRender : function(ct, position){
39137 Roo.form.Field.superclass.onRender.call(this, ct, position);
39139 var cfg = this.getAutoCreate();
39141 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39143 if (!cfg.name.length) {
39146 if(this.inputType){
39147 cfg.type = this.inputType;
39149 this.el = ct.createChild(cfg, position);
39151 var type = this.el.dom.type;
39153 if(type == 'password'){
39156 this.el.addClass('x-form-'+type);
39159 this.el.dom.readOnly = true;
39161 if(this.tabIndex !== undefined){
39162 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39165 this.el.addClass([this.fieldClass, this.cls]);
39170 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39171 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39172 * @return {Roo.form.Field} this
39174 applyTo : function(target){
39175 this.allowDomMove = false;
39176 this.el = Roo.get(target);
39177 this.render(this.el.dom.parentNode);
39182 initValue : function(){
39183 if(this.value !== undefined){
39184 this.setValue(this.value);
39185 }else if(this.el.dom.value.length > 0){
39186 this.setValue(this.el.dom.value);
39191 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39192 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39194 isDirty : function() {
39195 if(this.disabled) {
39198 return String(this.getValue()) !== String(this.originalValue);
39202 * stores the current value in loadedValue
39204 resetHasChanged : function()
39206 this.loadedValue = String(this.getValue());
39209 * checks the current value against the 'loaded' value.
39210 * Note - will return false if 'resetHasChanged' has not been called first.
39212 hasChanged : function()
39214 if(this.disabled || this.readOnly) {
39217 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39223 afterRender : function(){
39224 Roo.form.Field.superclass.afterRender.call(this);
39229 fireKey : function(e){
39230 //Roo.log('field ' + e.getKey());
39231 if(e.isNavKeyPress()){
39232 this.fireEvent("specialkey", this, e);
39237 * Resets the current field value to the originally loaded value and clears any validation messages
39239 reset : function(){
39240 this.setValue(this.resetValue);
39241 this.originalValue = this.getValue();
39242 this.clearInvalid();
39246 initEvents : function(){
39247 // safari killled keypress - so keydown is now used..
39248 this.el.on("keydown" , this.fireKey, this);
39249 this.el.on("focus", this.onFocus, this);
39250 this.el.on("blur", this.onBlur, this);
39251 this.el.relayEvent('keyup', this);
39253 // reference to original value for reset
39254 this.originalValue = this.getValue();
39255 this.resetValue = this.getValue();
39259 onFocus : function(){
39260 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39261 this.el.addClass(this.focusClass);
39263 if(!this.hasFocus){
39264 this.hasFocus = true;
39265 this.startValue = this.getValue();
39266 this.fireEvent("focus", this);
39270 beforeBlur : Roo.emptyFn,
39273 onBlur : function(){
39275 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39276 this.el.removeClass(this.focusClass);
39278 this.hasFocus = false;
39279 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39282 var v = this.getValue();
39283 if(String(v) !== String(this.startValue)){
39284 this.fireEvent('change', this, v, this.startValue);
39286 this.fireEvent("blur", this);
39290 * Returns whether or not the field value is currently valid
39291 * @param {Boolean} preventMark True to disable marking the field invalid
39292 * @return {Boolean} True if the value is valid, else false
39294 isValid : function(preventMark){
39298 var restore = this.preventMark;
39299 this.preventMark = preventMark === true;
39300 var v = this.validateValue(this.processValue(this.getRawValue()));
39301 this.preventMark = restore;
39306 * Validates the field value
39307 * @return {Boolean} True if the value is valid, else false
39309 validate : function(){
39310 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39311 this.clearInvalid();
39317 processValue : function(value){
39322 // Subclasses should provide the validation implementation by overriding this
39323 validateValue : function(value){
39328 * Mark this field as invalid
39329 * @param {String} msg The validation message
39331 markInvalid : function(msg){
39332 if(!this.rendered || this.preventMark){ // not rendered
39336 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39338 obj.el.addClass(this.invalidClass);
39339 msg = msg || this.invalidText;
39340 switch(this.msgTarget){
39342 obj.el.dom.qtip = msg;
39343 obj.el.dom.qclass = 'x-form-invalid-tip';
39344 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39345 Roo.QuickTips.enable();
39349 this.el.dom.title = msg;
39353 var elp = this.el.findParent('.x-form-element', 5, true);
39354 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39355 this.errorEl.setWidth(elp.getWidth(true)-20);
39357 this.errorEl.update(msg);
39358 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39361 if(!this.errorIcon){
39362 var elp = this.el.findParent('.x-form-element', 5, true);
39363 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39365 this.alignErrorIcon();
39366 this.errorIcon.dom.qtip = msg;
39367 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39368 this.errorIcon.show();
39369 this.on('resize', this.alignErrorIcon, this);
39372 var t = Roo.getDom(this.msgTarget);
39374 t.style.display = this.msgDisplay;
39377 this.fireEvent('invalid', this, msg);
39381 alignErrorIcon : function(){
39382 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39386 * Clear any invalid styles/messages for this field
39388 clearInvalid : function(){
39389 if(!this.rendered || this.preventMark){ // not rendered
39392 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39394 obj.el.removeClass(this.invalidClass);
39395 switch(this.msgTarget){
39397 obj.el.dom.qtip = '';
39400 this.el.dom.title = '';
39404 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39408 if(this.errorIcon){
39409 this.errorIcon.dom.qtip = '';
39410 this.errorIcon.hide();
39411 this.un('resize', this.alignErrorIcon, this);
39415 var t = Roo.getDom(this.msgTarget);
39417 t.style.display = 'none';
39420 this.fireEvent('valid', this);
39424 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39425 * @return {Mixed} value The field value
39427 getRawValue : function(){
39428 var v = this.el.getValue();
39434 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39435 * @return {Mixed} value The field value
39437 getValue : function(){
39438 var v = this.el.getValue();
39444 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39445 * @param {Mixed} value The value to set
39447 setRawValue : function(v){
39448 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39452 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39453 * @param {Mixed} value The value to set
39455 setValue : function(v){
39458 this.el.dom.value = (v === null || v === undefined ? '' : v);
39463 adjustSize : function(w, h){
39464 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39465 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39469 adjustWidth : function(tag, w){
39470 tag = tag.toLowerCase();
39471 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39472 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39473 if(tag == 'input'){
39476 if(tag == 'textarea'){
39479 }else if(Roo.isOpera){
39480 if(tag == 'input'){
39483 if(tag == 'textarea'){
39493 // anything other than normal should be considered experimental
39494 Roo.form.Field.msgFx = {
39496 show: function(msgEl, f){
39497 msgEl.setDisplayed('block');
39500 hide : function(msgEl, f){
39501 msgEl.setDisplayed(false).update('');
39506 show: function(msgEl, f){
39507 msgEl.slideIn('t', {stopFx:true});
39510 hide : function(msgEl, f){
39511 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39516 show: function(msgEl, f){
39517 msgEl.fixDisplay();
39518 msgEl.alignTo(f.el, 'tl-tr');
39519 msgEl.slideIn('l', {stopFx:true});
39522 hide : function(msgEl, f){
39523 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39528 * Ext JS Library 1.1.1
39529 * Copyright(c) 2006-2007, Ext JS, LLC.
39531 * Originally Released Under LGPL - original licence link has changed is not relivant.
39534 * <script type="text/javascript">
39539 * @class Roo.form.TextField
39540 * @extends Roo.form.Field
39541 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39542 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39544 * Creates a new TextField
39545 * @param {Object} config Configuration options
39547 Roo.form.TextField = function(config){
39548 Roo.form.TextField.superclass.constructor.call(this, config);
39552 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39553 * according to the default logic, but this event provides a hook for the developer to apply additional
39554 * logic at runtime to resize the field if needed.
39555 * @param {Roo.form.Field} this This text field
39556 * @param {Number} width The new field width
39562 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39564 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39568 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39572 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39576 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39580 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39584 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39586 disableKeyFilter : false,
39588 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39592 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39596 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39598 maxLength : Number.MAX_VALUE,
39600 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39602 minLengthText : "The minimum length for this field is {0}",
39604 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39606 maxLengthText : "The maximum length for this field is {0}",
39608 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39610 selectOnFocus : false,
39612 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39614 allowLeadingSpace : false,
39616 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39618 blankText : "This field is required",
39620 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39621 * If available, this function will be called only after the basic validators all return true, and will be passed the
39622 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39626 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39627 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39628 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39632 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39636 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39642 initEvents : function()
39644 if (this.emptyText) {
39645 this.el.attr('placeholder', this.emptyText);
39648 Roo.form.TextField.superclass.initEvents.call(this);
39649 if(this.validationEvent == 'keyup'){
39650 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39651 this.el.on('keyup', this.filterValidation, this);
39653 else if(this.validationEvent !== false){
39654 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39657 if(this.selectOnFocus){
39658 this.on("focus", this.preFocus, this);
39660 if (!this.allowLeadingSpace) {
39661 this.on('blur', this.cleanLeadingSpace, this);
39664 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39665 this.el.on("keypress", this.filterKeys, this);
39668 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39669 this.el.on("click", this.autoSize, this);
39671 if(this.el.is('input[type=password]') && Roo.isSafari){
39672 this.el.on('keydown', this.SafariOnKeyDown, this);
39676 processValue : function(value){
39677 if(this.stripCharsRe){
39678 var newValue = value.replace(this.stripCharsRe, '');
39679 if(newValue !== value){
39680 this.setRawValue(newValue);
39687 filterValidation : function(e){
39688 if(!e.isNavKeyPress()){
39689 this.validationTask.delay(this.validationDelay);
39694 onKeyUp : function(e){
39695 if(!e.isNavKeyPress()){
39699 // private - clean the leading white space
39700 cleanLeadingSpace : function(e)
39702 if ( this.inputType == 'file') {
39706 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39709 * Resets the current field value to the originally-loaded value and clears any validation messages.
39712 reset : function(){
39713 Roo.form.TextField.superclass.reset.call(this);
39717 preFocus : function(){
39719 if(this.selectOnFocus){
39720 this.el.dom.select();
39726 filterKeys : function(e){
39727 var k = e.getKey();
39728 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39731 var c = e.getCharCode(), cc = String.fromCharCode(c);
39732 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39735 if(!this.maskRe.test(cc)){
39740 setValue : function(v){
39742 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39748 * Validates a value according to the field's validation rules and marks the field as invalid
39749 * if the validation fails
39750 * @param {Mixed} value The value to validate
39751 * @return {Boolean} True if the value is valid, else false
39753 validateValue : function(value){
39754 if(value.length < 1) { // if it's blank
39755 if(this.allowBlank){
39756 this.clearInvalid();
39759 this.markInvalid(this.blankText);
39763 if(value.length < this.minLength){
39764 this.markInvalid(String.format(this.minLengthText, this.minLength));
39767 if(value.length > this.maxLength){
39768 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39772 var vt = Roo.form.VTypes;
39773 if(!vt[this.vtype](value, this)){
39774 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39778 if(typeof this.validator == "function"){
39779 var msg = this.validator(value);
39781 this.markInvalid(msg);
39785 if(this.regex && !this.regex.test(value)){
39786 this.markInvalid(this.regexText);
39793 * Selects text in this field
39794 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39795 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39797 selectText : function(start, end){
39798 var v = this.getRawValue();
39800 start = start === undefined ? 0 : start;
39801 end = end === undefined ? v.length : end;
39802 var d = this.el.dom;
39803 if(d.setSelectionRange){
39804 d.setSelectionRange(start, end);
39805 }else if(d.createTextRange){
39806 var range = d.createTextRange();
39807 range.moveStart("character", start);
39808 range.moveEnd("character", v.length-end);
39815 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39816 * This only takes effect if grow = true, and fires the autosize event.
39818 autoSize : function(){
39819 if(!this.grow || !this.rendered){
39823 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39826 var v = el.dom.value;
39827 var d = document.createElement('div');
39828 d.appendChild(document.createTextNode(v));
39832 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39833 this.el.setWidth(w);
39834 this.fireEvent("autosize", this, w);
39838 SafariOnKeyDown : function(event)
39840 // this is a workaround for a password hang bug on chrome/ webkit.
39842 var isSelectAll = false;
39844 if(this.el.dom.selectionEnd > 0){
39845 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39847 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39848 event.preventDefault();
39853 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39855 event.preventDefault();
39856 // this is very hacky as keydown always get's upper case.
39858 var cc = String.fromCharCode(event.getCharCode());
39861 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39869 * Ext JS Library 1.1.1
39870 * Copyright(c) 2006-2007, Ext JS, LLC.
39872 * Originally Released Under LGPL - original licence link has changed is not relivant.
39875 * <script type="text/javascript">
39879 * @class Roo.form.Hidden
39880 * @extends Roo.form.TextField
39881 * Simple Hidden element used on forms
39883 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39886 * Creates a new Hidden form element.
39887 * @param {Object} config Configuration options
39892 // easy hidden field...
39893 Roo.form.Hidden = function(config){
39894 Roo.form.Hidden.superclass.constructor.call(this, config);
39897 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39899 inputType: 'hidden',
39902 labelSeparator: '',
39904 itemCls : 'x-form-item-display-none'
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.TriggerField
39923 * @extends Roo.form.TextField
39924 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39925 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39926 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39927 * for which you can provide a custom implementation. For example:
39929 var trigger = new Roo.form.TriggerField();
39930 trigger.onTriggerClick = myTriggerFn;
39931 trigger.applyTo('my-field');
39934 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39935 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39936 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39937 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39939 * Create a new TriggerField.
39940 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39941 * to the base TextField)
39943 Roo.form.TriggerField = function(config){
39944 this.mimicing = false;
39945 Roo.form.TriggerField.superclass.constructor.call(this, config);
39948 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39950 * @cfg {String} triggerClass A CSS class to apply to the trigger
39953 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39954 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39956 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39958 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39962 /** @cfg {Boolean} grow @hide */
39963 /** @cfg {Number} growMin @hide */
39964 /** @cfg {Number} growMax @hide */
39970 autoSize: Roo.emptyFn,
39974 deferHeight : true,
39977 actionMode : 'wrap',
39979 onResize : function(w, h){
39980 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39981 if(typeof w == 'number'){
39982 var x = w - this.trigger.getWidth();
39983 this.el.setWidth(this.adjustWidth('input', x));
39984 this.trigger.setStyle('left', x+'px');
39989 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39992 getResizeEl : function(){
39997 getPositionEl : function(){
40002 alignErrorIcon : function(){
40003 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40007 onRender : function(ct, position){
40008 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40009 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
40010 this.trigger = this.wrap.createChild(this.triggerConfig ||
40011 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
40012 if(this.hideTrigger){
40013 this.trigger.setDisplayed(false);
40015 this.initTrigger();
40017 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
40022 initTrigger : function(){
40023 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40024 this.trigger.addClassOnOver('x-form-trigger-over');
40025 this.trigger.addClassOnClick('x-form-trigger-click');
40029 onDestroy : function(){
40031 this.trigger.removeAllListeners();
40032 this.trigger.remove();
40035 this.wrap.remove();
40037 Roo.form.TriggerField.superclass.onDestroy.call(this);
40041 onFocus : function(){
40042 Roo.form.TriggerField.superclass.onFocus.call(this);
40043 if(!this.mimicing){
40044 this.wrap.addClass('x-trigger-wrap-focus');
40045 this.mimicing = true;
40046 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40047 if(this.monitorTab){
40048 this.el.on("keydown", this.checkTab, this);
40054 checkTab : function(e){
40055 if(e.getKey() == e.TAB){
40056 this.triggerBlur();
40061 onBlur : function(){
40066 mimicBlur : function(e, t){
40067 if(!this.wrap.contains(t) && this.validateBlur()){
40068 this.triggerBlur();
40073 triggerBlur : function(){
40074 this.mimicing = false;
40075 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40076 if(this.monitorTab){
40077 this.el.un("keydown", this.checkTab, this);
40079 this.wrap.removeClass('x-trigger-wrap-focus');
40080 Roo.form.TriggerField.superclass.onBlur.call(this);
40084 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40085 validateBlur : function(e, t){
40090 onDisable : function(){
40091 Roo.form.TriggerField.superclass.onDisable.call(this);
40093 this.wrap.addClass('x-item-disabled');
40098 onEnable : function(){
40099 Roo.form.TriggerField.superclass.onEnable.call(this);
40101 this.wrap.removeClass('x-item-disabled');
40106 onShow : function(){
40107 var ae = this.getActionEl();
40110 ae.dom.style.display = '';
40111 ae.dom.style.visibility = 'visible';
40117 onHide : function(){
40118 var ae = this.getActionEl();
40119 ae.dom.style.display = 'none';
40123 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40124 * by an implementing function.
40126 * @param {EventObject} e
40128 onTriggerClick : Roo.emptyFn
40131 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40132 // to be extended by an implementing class. For an example of implementing this class, see the custom
40133 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40134 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40135 initComponent : function(){
40136 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40138 this.triggerConfig = {
40139 tag:'span', cls:'x-form-twin-triggers', cn:[
40140 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40141 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40145 getTrigger : function(index){
40146 return this.triggers[index];
40149 initTrigger : function(){
40150 var ts = this.trigger.select('.x-form-trigger', true);
40151 this.wrap.setStyle('overflow', 'hidden');
40152 var triggerField = this;
40153 ts.each(function(t, all, index){
40154 t.hide = function(){
40155 var w = triggerField.wrap.getWidth();
40156 this.dom.style.display = 'none';
40157 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40159 t.show = function(){
40160 var w = triggerField.wrap.getWidth();
40161 this.dom.style.display = '';
40162 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40164 var triggerIndex = 'Trigger'+(index+1);
40166 if(this['hide'+triggerIndex]){
40167 t.dom.style.display = 'none';
40169 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40170 t.addClassOnOver('x-form-trigger-over');
40171 t.addClassOnClick('x-form-trigger-click');
40173 this.triggers = ts.elements;
40176 onTrigger1Click : Roo.emptyFn,
40177 onTrigger2Click : Roo.emptyFn
40180 * Ext JS Library 1.1.1
40181 * Copyright(c) 2006-2007, Ext JS, LLC.
40183 * Originally Released Under LGPL - original licence link has changed is not relivant.
40186 * <script type="text/javascript">
40190 * @class Roo.form.TextArea
40191 * @extends Roo.form.TextField
40192 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40193 * support for auto-sizing.
40195 * Creates a new TextArea
40196 * @param {Object} config Configuration options
40198 Roo.form.TextArea = function(config){
40199 Roo.form.TextArea.superclass.constructor.call(this, config);
40200 // these are provided exchanges for backwards compat
40201 // minHeight/maxHeight were replaced by growMin/growMax to be
40202 // compatible with TextField growing config values
40203 if(this.minHeight !== undefined){
40204 this.growMin = this.minHeight;
40206 if(this.maxHeight !== undefined){
40207 this.growMax = this.maxHeight;
40211 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40213 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40217 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40221 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40222 * in the field (equivalent to setting overflow: hidden, defaults to false)
40224 preventScrollbars: false,
40226 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40227 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40231 onRender : function(ct, position){
40233 this.defaultAutoCreate = {
40235 style:"width:300px;height:60px;",
40236 autocomplete: "new-password"
40239 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40241 this.textSizeEl = Roo.DomHelper.append(document.body, {
40242 tag: "pre", cls: "x-form-grow-sizer"
40244 if(this.preventScrollbars){
40245 this.el.setStyle("overflow", "hidden");
40247 this.el.setHeight(this.growMin);
40251 onDestroy : function(){
40252 if(this.textSizeEl){
40253 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40255 Roo.form.TextArea.superclass.onDestroy.call(this);
40259 onKeyUp : function(e){
40260 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40266 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40267 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40269 autoSize : function(){
40270 if(!this.grow || !this.textSizeEl){
40274 var v = el.dom.value;
40275 var ts = this.textSizeEl;
40278 ts.appendChild(document.createTextNode(v));
40281 Roo.fly(ts).setWidth(this.el.getWidth());
40283 v = "  ";
40286 v = v.replace(/\n/g, '<p> </p>');
40288 v += " \n ";
40291 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40292 if(h != this.lastHeight){
40293 this.lastHeight = h;
40294 this.el.setHeight(h);
40295 this.fireEvent("autosize", this, h);
40300 * Ext JS Library 1.1.1
40301 * Copyright(c) 2006-2007, Ext JS, LLC.
40303 * Originally Released Under LGPL - original licence link has changed is not relivant.
40306 * <script type="text/javascript">
40311 * @class Roo.form.NumberField
40312 * @extends Roo.form.TextField
40313 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40315 * Creates a new NumberField
40316 * @param {Object} config Configuration options
40318 Roo.form.NumberField = function(config){
40319 Roo.form.NumberField.superclass.constructor.call(this, config);
40322 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40324 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40326 fieldClass: "x-form-field x-form-num-field",
40328 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40330 allowDecimals : true,
40332 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40334 decimalSeparator : ".",
40336 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40338 decimalPrecision : 2,
40340 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40342 allowNegative : true,
40344 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40346 minValue : Number.NEGATIVE_INFINITY,
40348 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40350 maxValue : Number.MAX_VALUE,
40352 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40354 minText : "The minimum value for this field is {0}",
40356 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40358 maxText : "The maximum value for this field is {0}",
40360 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40361 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40363 nanText : "{0} is not a valid number",
40366 initEvents : function(){
40367 Roo.form.NumberField.superclass.initEvents.call(this);
40368 var allowed = "0123456789";
40369 if(this.allowDecimals){
40370 allowed += this.decimalSeparator;
40372 if(this.allowNegative){
40375 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40376 var keyPress = function(e){
40377 var k = e.getKey();
40378 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40381 var c = e.getCharCode();
40382 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40386 this.el.on("keypress", keyPress, this);
40390 validateValue : function(value){
40391 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40394 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40397 var num = this.parseValue(value);
40399 this.markInvalid(String.format(this.nanText, value));
40402 if(num < this.minValue){
40403 this.markInvalid(String.format(this.minText, this.minValue));
40406 if(num > this.maxValue){
40407 this.markInvalid(String.format(this.maxText, this.maxValue));
40413 getValue : function(){
40414 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40418 parseValue : function(value){
40419 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40420 return isNaN(value) ? '' : value;
40424 fixPrecision : function(value){
40425 var nan = isNaN(value);
40426 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40427 return nan ? '' : value;
40429 return parseFloat(value).toFixed(this.decimalPrecision);
40432 setValue : function(v){
40433 v = this.fixPrecision(v);
40434 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40438 decimalPrecisionFcn : function(v){
40439 return Math.floor(v);
40442 beforeBlur : function(){
40443 var v = this.parseValue(this.getRawValue());
40450 * Ext JS Library 1.1.1
40451 * Copyright(c) 2006-2007, Ext JS, LLC.
40453 * Originally Released Under LGPL - original licence link has changed is not relivant.
40456 * <script type="text/javascript">
40460 * @class Roo.form.DateField
40461 * @extends Roo.form.TriggerField
40462 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40464 * Create a new DateField
40465 * @param {Object} config
40467 Roo.form.DateField = function(config)
40469 Roo.form.DateField.superclass.constructor.call(this, config);
40475 * Fires when a date is selected
40476 * @param {Roo.form.DateField} combo This combo box
40477 * @param {Date} date The date selected
40484 if(typeof this.minValue == "string") {
40485 this.minValue = this.parseDate(this.minValue);
40487 if(typeof this.maxValue == "string") {
40488 this.maxValue = this.parseDate(this.maxValue);
40490 this.ddMatch = null;
40491 if(this.disabledDates){
40492 var dd = this.disabledDates;
40494 for(var i = 0; i < dd.length; i++){
40496 if(i != dd.length-1) {
40500 this.ddMatch = new RegExp(re + ")");
40504 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40506 * @cfg {String} format
40507 * The default date format string which can be overriden for localization support. The format must be
40508 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40512 * @cfg {String} altFormats
40513 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40514 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40516 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40518 * @cfg {Array} disabledDays
40519 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40521 disabledDays : null,
40523 * @cfg {String} disabledDaysText
40524 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40526 disabledDaysText : "Disabled",
40528 * @cfg {Array} disabledDates
40529 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40530 * expression so they are very powerful. Some examples:
40532 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40533 * <li>["03/08", "09/16"] would disable those days for every year</li>
40534 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40535 * <li>["03/../2006"] would disable every day in March 2006</li>
40536 * <li>["^03"] would disable every day in every March</li>
40538 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40539 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40541 disabledDates : null,
40543 * @cfg {String} disabledDatesText
40544 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40546 disabledDatesText : "Disabled",
40548 * @cfg {Date/String} minValue
40549 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40550 * valid format (defaults to null).
40554 * @cfg {Date/String} maxValue
40555 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40556 * valid format (defaults to null).
40560 * @cfg {String} minText
40561 * The error text to display when the date in the cell is before minValue (defaults to
40562 * 'The date in this field must be after {minValue}').
40564 minText : "The date in this field must be equal to or after {0}",
40566 * @cfg {String} maxText
40567 * The error text to display when the date in the cell is after maxValue (defaults to
40568 * 'The date in this field must be before {maxValue}').
40570 maxText : "The date in this field must be equal to or before {0}",
40572 * @cfg {String} invalidText
40573 * The error text to display when the date in the field is invalid (defaults to
40574 * '{value} is not a valid date - it must be in the format {format}').
40576 invalidText : "{0} is not a valid date - it must be in the format {1}",
40578 * @cfg {String} triggerClass
40579 * An additional CSS class used to style the trigger button. The trigger will always get the
40580 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40581 * which displays a calendar icon).
40583 triggerClass : 'x-form-date-trigger',
40587 * @cfg {Boolean} useIso
40588 * if enabled, then the date field will use a hidden field to store the
40589 * real value as iso formated date. default (false)
40593 * @cfg {String/Object} autoCreate
40594 * A DomHelper element spec, or true for a default element spec (defaults to
40595 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40598 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40601 hiddenField: false,
40603 onRender : function(ct, position)
40605 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40607 //this.el.dom.removeAttribute('name');
40608 Roo.log("Changing name?");
40609 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40610 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40612 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40613 // prevent input submission
40614 this.hiddenName = this.name;
40621 validateValue : function(value)
40623 value = this.formatDate(value);
40624 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40625 Roo.log('super failed');
40628 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40631 var svalue = value;
40632 value = this.parseDate(value);
40634 Roo.log('parse date failed' + svalue);
40635 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40638 var time = value.getTime();
40639 if(this.minValue && time < this.minValue.getTime()){
40640 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40643 if(this.maxValue && time > this.maxValue.getTime()){
40644 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40647 if(this.disabledDays){
40648 var day = value.getDay();
40649 for(var i = 0; i < this.disabledDays.length; i++) {
40650 if(day === this.disabledDays[i]){
40651 this.markInvalid(this.disabledDaysText);
40656 var fvalue = this.formatDate(value);
40657 if(this.ddMatch && this.ddMatch.test(fvalue)){
40658 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40665 // Provides logic to override the default TriggerField.validateBlur which just returns true
40666 validateBlur : function(){
40667 return !this.menu || !this.menu.isVisible();
40670 getName: function()
40672 // returns hidden if it's set..
40673 if (!this.rendered) {return ''};
40674 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40679 * Returns the current date value of the date field.
40680 * @return {Date} The date value
40682 getValue : function(){
40684 return this.hiddenField ?
40685 this.hiddenField.value :
40686 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40690 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40691 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40692 * (the default format used is "m/d/y").
40695 //All of these calls set the same date value (May 4, 2006)
40697 //Pass a date object:
40698 var dt = new Date('5/4/06');
40699 dateField.setValue(dt);
40701 //Pass a date string (default format):
40702 dateField.setValue('5/4/06');
40704 //Pass a date string (custom format):
40705 dateField.format = 'Y-m-d';
40706 dateField.setValue('2006-5-4');
40708 * @param {String/Date} date The date or valid date string
40710 setValue : function(date){
40711 if (this.hiddenField) {
40712 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40714 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40715 // make sure the value field is always stored as a date..
40716 this.value = this.parseDate(date);
40722 parseDate : function(value){
40723 if(!value || value instanceof Date){
40726 var v = Date.parseDate(value, this.format);
40727 if (!v && this.useIso) {
40728 v = Date.parseDate(value, 'Y-m-d');
40730 if(!v && this.altFormats){
40731 if(!this.altFormatsArray){
40732 this.altFormatsArray = this.altFormats.split("|");
40734 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40735 v = Date.parseDate(value, this.altFormatsArray[i]);
40742 formatDate : function(date, fmt){
40743 return (!date || !(date instanceof Date)) ?
40744 date : date.dateFormat(fmt || this.format);
40749 select: function(m, d){
40752 this.fireEvent('select', this, d);
40754 show : function(){ // retain focus styling
40758 this.focus.defer(10, this);
40759 var ml = this.menuListeners;
40760 this.menu.un("select", ml.select, this);
40761 this.menu.un("show", ml.show, this);
40762 this.menu.un("hide", ml.hide, this);
40767 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40768 onTriggerClick : function(){
40772 if(this.menu == null){
40773 this.menu = new Roo.menu.DateMenu();
40775 Roo.apply(this.menu.picker, {
40776 showClear: this.allowBlank,
40777 minDate : this.minValue,
40778 maxDate : this.maxValue,
40779 disabledDatesRE : this.ddMatch,
40780 disabledDatesText : this.disabledDatesText,
40781 disabledDays : this.disabledDays,
40782 disabledDaysText : this.disabledDaysText,
40783 format : this.useIso ? 'Y-m-d' : this.format,
40784 minText : String.format(this.minText, this.formatDate(this.minValue)),
40785 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40787 this.menu.on(Roo.apply({}, this.menuListeners, {
40790 this.menu.picker.setValue(this.getValue() || new Date());
40791 this.menu.show(this.el, "tl-bl?");
40794 beforeBlur : function(){
40795 var v = this.parseDate(this.getRawValue());
40805 isDirty : function() {
40806 if(this.disabled) {
40810 if(typeof(this.startValue) === 'undefined'){
40814 return String(this.getValue()) !== String(this.startValue);
40818 cleanLeadingSpace : function(e)
40825 * Ext JS Library 1.1.1
40826 * Copyright(c) 2006-2007, Ext JS, LLC.
40828 * Originally Released Under LGPL - original licence link has changed is not relivant.
40831 * <script type="text/javascript">
40835 * @class Roo.form.MonthField
40836 * @extends Roo.form.TriggerField
40837 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40839 * Create a new MonthField
40840 * @param {Object} config
40842 Roo.form.MonthField = function(config){
40844 Roo.form.MonthField.superclass.constructor.call(this, config);
40850 * Fires when a date is selected
40851 * @param {Roo.form.MonthFieeld} combo This combo box
40852 * @param {Date} date The date selected
40859 if(typeof this.minValue == "string") {
40860 this.minValue = this.parseDate(this.minValue);
40862 if(typeof this.maxValue == "string") {
40863 this.maxValue = this.parseDate(this.maxValue);
40865 this.ddMatch = null;
40866 if(this.disabledDates){
40867 var dd = this.disabledDates;
40869 for(var i = 0; i < dd.length; i++){
40871 if(i != dd.length-1) {
40875 this.ddMatch = new RegExp(re + ")");
40879 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40881 * @cfg {String} format
40882 * The default date format string which can be overriden for localization support. The format must be
40883 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40887 * @cfg {String} altFormats
40888 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40889 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40891 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40893 * @cfg {Array} disabledDays
40894 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40896 disabledDays : [0,1,2,3,4,5,6],
40898 * @cfg {String} disabledDaysText
40899 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40901 disabledDaysText : "Disabled",
40903 * @cfg {Array} disabledDates
40904 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40905 * expression so they are very powerful. Some examples:
40907 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40908 * <li>["03/08", "09/16"] would disable those days for every year</li>
40909 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40910 * <li>["03/../2006"] would disable every day in March 2006</li>
40911 * <li>["^03"] would disable every day in every March</li>
40913 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40914 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40916 disabledDates : null,
40918 * @cfg {String} disabledDatesText
40919 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40921 disabledDatesText : "Disabled",
40923 * @cfg {Date/String} minValue
40924 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40925 * valid format (defaults to null).
40929 * @cfg {Date/String} maxValue
40930 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40931 * valid format (defaults to null).
40935 * @cfg {String} minText
40936 * The error text to display when the date in the cell is before minValue (defaults to
40937 * 'The date in this field must be after {minValue}').
40939 minText : "The date in this field must be equal to or after {0}",
40941 * @cfg {String} maxTextf
40942 * The error text to display when the date in the cell is after maxValue (defaults to
40943 * 'The date in this field must be before {maxValue}').
40945 maxText : "The date in this field must be equal to or before {0}",
40947 * @cfg {String} invalidText
40948 * The error text to display when the date in the field is invalid (defaults to
40949 * '{value} is not a valid date - it must be in the format {format}').
40951 invalidText : "{0} is not a valid date - it must be in the format {1}",
40953 * @cfg {String} triggerClass
40954 * An additional CSS class used to style the trigger button. The trigger will always get the
40955 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40956 * which displays a calendar icon).
40958 triggerClass : 'x-form-date-trigger',
40962 * @cfg {Boolean} useIso
40963 * if enabled, then the date field will use a hidden field to store the
40964 * real value as iso formated date. default (true)
40968 * @cfg {String/Object} autoCreate
40969 * A DomHelper element spec, or true for a default element spec (defaults to
40970 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40973 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40976 hiddenField: false,
40978 hideMonthPicker : false,
40980 onRender : function(ct, position)
40982 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40984 this.el.dom.removeAttribute('name');
40985 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40987 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40988 // prevent input submission
40989 this.hiddenName = this.name;
40996 validateValue : function(value)
40998 value = this.formatDate(value);
40999 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41002 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41005 var svalue = value;
41006 value = this.parseDate(value);
41008 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41011 var time = value.getTime();
41012 if(this.minValue && time < this.minValue.getTime()){
41013 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41016 if(this.maxValue && time > this.maxValue.getTime()){
41017 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41020 /*if(this.disabledDays){
41021 var day = value.getDay();
41022 for(var i = 0; i < this.disabledDays.length; i++) {
41023 if(day === this.disabledDays[i]){
41024 this.markInvalid(this.disabledDaysText);
41030 var fvalue = this.formatDate(value);
41031 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41032 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41040 // Provides logic to override the default TriggerField.validateBlur which just returns true
41041 validateBlur : function(){
41042 return !this.menu || !this.menu.isVisible();
41046 * Returns the current date value of the date field.
41047 * @return {Date} The date value
41049 getValue : function(){
41053 return this.hiddenField ?
41054 this.hiddenField.value :
41055 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41059 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41060 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41061 * (the default format used is "m/d/y").
41064 //All of these calls set the same date value (May 4, 2006)
41066 //Pass a date object:
41067 var dt = new Date('5/4/06');
41068 monthField.setValue(dt);
41070 //Pass a date string (default format):
41071 monthField.setValue('5/4/06');
41073 //Pass a date string (custom format):
41074 monthField.format = 'Y-m-d';
41075 monthField.setValue('2006-5-4');
41077 * @param {String/Date} date The date or valid date string
41079 setValue : function(date){
41080 Roo.log('month setValue' + date);
41081 // can only be first of month..
41083 var val = this.parseDate(date);
41085 if (this.hiddenField) {
41086 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41088 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41089 this.value = this.parseDate(date);
41093 parseDate : function(value){
41094 if(!value || value instanceof Date){
41095 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41098 var v = Date.parseDate(value, this.format);
41099 if (!v && this.useIso) {
41100 v = Date.parseDate(value, 'Y-m-d');
41104 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41108 if(!v && this.altFormats){
41109 if(!this.altFormatsArray){
41110 this.altFormatsArray = this.altFormats.split("|");
41112 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41113 v = Date.parseDate(value, this.altFormatsArray[i]);
41120 formatDate : function(date, fmt){
41121 return (!date || !(date instanceof Date)) ?
41122 date : date.dateFormat(fmt || this.format);
41127 select: function(m, d){
41129 this.fireEvent('select', this, d);
41131 show : function(){ // retain focus styling
41135 this.focus.defer(10, this);
41136 var ml = this.menuListeners;
41137 this.menu.un("select", ml.select, this);
41138 this.menu.un("show", ml.show, this);
41139 this.menu.un("hide", ml.hide, this);
41143 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41144 onTriggerClick : function(){
41148 if(this.menu == null){
41149 this.menu = new Roo.menu.DateMenu();
41153 Roo.apply(this.menu.picker, {
41155 showClear: this.allowBlank,
41156 minDate : this.minValue,
41157 maxDate : this.maxValue,
41158 disabledDatesRE : this.ddMatch,
41159 disabledDatesText : this.disabledDatesText,
41161 format : this.useIso ? 'Y-m-d' : this.format,
41162 minText : String.format(this.minText, this.formatDate(this.minValue)),
41163 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41166 this.menu.on(Roo.apply({}, this.menuListeners, {
41174 // hide month picker get's called when we called by 'before hide';
41176 var ignorehide = true;
41177 p.hideMonthPicker = function(disableAnim){
41181 if(this.monthPicker){
41182 Roo.log("hideMonthPicker called");
41183 if(disableAnim === true){
41184 this.monthPicker.hide();
41186 this.monthPicker.slideOut('t', {duration:.2});
41187 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41188 p.fireEvent("select", this, this.value);
41194 Roo.log('picker set value');
41195 Roo.log(this.getValue());
41196 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41197 m.show(this.el, 'tl-bl?');
41198 ignorehide = false;
41199 // this will trigger hideMonthPicker..
41202 // hidden the day picker
41203 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41209 p.showMonthPicker.defer(100, p);
41215 beforeBlur : function(){
41216 var v = this.parseDate(this.getRawValue());
41222 /** @cfg {Boolean} grow @hide */
41223 /** @cfg {Number} growMin @hide */
41224 /** @cfg {Number} growMax @hide */
41231 * Ext JS Library 1.1.1
41232 * Copyright(c) 2006-2007, Ext JS, LLC.
41234 * Originally Released Under LGPL - original licence link has changed is not relivant.
41237 * <script type="text/javascript">
41242 * @class Roo.form.ComboBox
41243 * @extends Roo.form.TriggerField
41244 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41246 * Create a new ComboBox.
41247 * @param {Object} config Configuration options
41249 Roo.form.ComboBox = function(config){
41250 Roo.form.ComboBox.superclass.constructor.call(this, config);
41254 * Fires when the dropdown list is expanded
41255 * @param {Roo.form.ComboBox} combo This combo box
41260 * Fires when the dropdown list is collapsed
41261 * @param {Roo.form.ComboBox} combo This combo box
41265 * @event beforeselect
41266 * Fires before a list item is selected. Return false to cancel the selection.
41267 * @param {Roo.form.ComboBox} combo This combo box
41268 * @param {Roo.data.Record} record The data record returned from the underlying store
41269 * @param {Number} index The index of the selected item in the dropdown list
41271 'beforeselect' : true,
41274 * Fires when a list item is selected
41275 * @param {Roo.form.ComboBox} combo This combo box
41276 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41277 * @param {Number} index The index of the selected item in the dropdown list
41281 * @event beforequery
41282 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41283 * The event object passed has these properties:
41284 * @param {Roo.form.ComboBox} combo This combo box
41285 * @param {String} query The query
41286 * @param {Boolean} forceAll true to force "all" query
41287 * @param {Boolean} cancel true to cancel the query
41288 * @param {Object} e The query event object
41290 'beforequery': true,
41293 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41294 * @param {Roo.form.ComboBox} combo This combo box
41299 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41300 * @param {Roo.form.ComboBox} combo This combo box
41301 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41307 if(this.transform){
41308 this.allowDomMove = false;
41309 var s = Roo.getDom(this.transform);
41310 if(!this.hiddenName){
41311 this.hiddenName = s.name;
41314 this.mode = 'local';
41315 var d = [], opts = s.options;
41316 for(var i = 0, len = opts.length;i < len; i++){
41318 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41320 this.value = value;
41322 d.push([value, o.text]);
41324 this.store = new Roo.data.SimpleStore({
41326 fields: ['value', 'text'],
41329 this.valueField = 'value';
41330 this.displayField = 'text';
41332 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41333 if(!this.lazyRender){
41334 this.target = true;
41335 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41336 s.parentNode.removeChild(s); // remove it
41337 this.render(this.el.parentNode);
41339 s.parentNode.removeChild(s); // remove it
41344 this.store = Roo.factory(this.store, Roo.data);
41347 this.selectedIndex = -1;
41348 if(this.mode == 'local'){
41349 if(config.queryDelay === undefined){
41350 this.queryDelay = 10;
41352 if(config.minChars === undefined){
41358 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41360 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41363 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41364 * rendering into an Roo.Editor, defaults to false)
41367 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41368 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41371 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41374 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41375 * the dropdown list (defaults to undefined, with no header element)
41379 * @cfg {String/Roo.Template} tpl The template to use to render the output
41383 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41385 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41387 listWidth: undefined,
41389 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41390 * mode = 'remote' or 'text' if mode = 'local')
41392 displayField: undefined,
41394 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41395 * mode = 'remote' or 'value' if mode = 'local').
41396 * Note: use of a valueField requires the user make a selection
41397 * in order for a value to be mapped.
41399 valueField: undefined,
41403 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41404 * field's data value (defaults to the underlying DOM element's name)
41406 hiddenName: undefined,
41408 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41412 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41414 selectedClass: 'x-combo-selected',
41416 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41417 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41418 * which displays a downward arrow icon).
41420 triggerClass : 'x-form-arrow-trigger',
41422 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41426 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41427 * anchor positions (defaults to 'tl-bl')
41429 listAlign: 'tl-bl?',
41431 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41435 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41436 * query specified by the allQuery config option (defaults to 'query')
41438 triggerAction: 'query',
41440 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41441 * (defaults to 4, does not apply if editable = false)
41445 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41446 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41450 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41451 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41455 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41456 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41460 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41461 * when editable = true (defaults to false)
41463 selectOnFocus:false,
41465 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41467 queryParam: 'query',
41469 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41470 * when mode = 'remote' (defaults to 'Loading...')
41472 loadingText: 'Loading...',
41474 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41478 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41482 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41483 * traditional select (defaults to true)
41487 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41491 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41495 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41496 * listWidth has a higher value)
41500 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41501 * allow the user to set arbitrary text into the field (defaults to false)
41503 forceSelection:false,
41505 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41506 * if typeAhead = true (defaults to 250)
41508 typeAheadDelay : 250,
41510 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41511 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41513 valueNotFoundText : undefined,
41515 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41517 blockFocus : false,
41520 * @cfg {Boolean} disableClear Disable showing of clear button.
41522 disableClear : false,
41524 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41526 alwaysQuery : false,
41532 // element that contains real text value.. (when hidden is used..)
41535 onRender : function(ct, position)
41537 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41539 if(this.hiddenName){
41540 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41542 this.hiddenField.value =
41543 this.hiddenValue !== undefined ? this.hiddenValue :
41544 this.value !== undefined ? this.value : '';
41546 // prevent input submission
41547 this.el.dom.removeAttribute('name');
41553 this.el.dom.setAttribute('autocomplete', 'off');
41556 var cls = 'x-combo-list';
41558 this.list = new Roo.Layer({
41559 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41562 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41563 this.list.setWidth(lw);
41564 this.list.swallowEvent('mousewheel');
41565 this.assetHeight = 0;
41568 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41569 this.assetHeight += this.header.getHeight();
41572 this.innerList = this.list.createChild({cls:cls+'-inner'});
41573 this.innerList.on('mouseover', this.onViewOver, this);
41574 this.innerList.on('mousemove', this.onViewMove, this);
41575 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41577 if(this.allowBlank && !this.pageSize && !this.disableClear){
41578 this.footer = this.list.createChild({cls:cls+'-ft'});
41579 this.pageTb = new Roo.Toolbar(this.footer);
41583 this.footer = this.list.createChild({cls:cls+'-ft'});
41584 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41585 {pageSize: this.pageSize});
41589 if (this.pageTb && this.allowBlank && !this.disableClear) {
41591 this.pageTb.add(new Roo.Toolbar.Fill(), {
41592 cls: 'x-btn-icon x-btn-clear',
41594 handler: function()
41597 _this.clearValue();
41598 _this.onSelect(false, -1);
41603 this.assetHeight += this.footer.getHeight();
41608 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41611 this.view = new Roo.View(this.innerList, this.tpl, {
41614 selectedClass: this.selectedClass
41617 this.view.on('click', this.onViewClick, this);
41619 this.store.on('beforeload', this.onBeforeLoad, this);
41620 this.store.on('load', this.onLoad, this);
41621 this.store.on('loadexception', this.onLoadException, this);
41623 if(this.resizable){
41624 this.resizer = new Roo.Resizable(this.list, {
41625 pinned:true, handles:'se'
41627 this.resizer.on('resize', function(r, w, h){
41628 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41629 this.listWidth = w;
41630 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41631 this.restrictHeight();
41633 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41635 if(!this.editable){
41636 this.editable = true;
41637 this.setEditable(false);
41641 if (typeof(this.events.add.listeners) != 'undefined') {
41643 this.addicon = this.wrap.createChild(
41644 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41646 this.addicon.on('click', function(e) {
41647 this.fireEvent('add', this);
41650 if (typeof(this.events.edit.listeners) != 'undefined') {
41652 this.editicon = this.wrap.createChild(
41653 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41654 if (this.addicon) {
41655 this.editicon.setStyle('margin-left', '40px');
41657 this.editicon.on('click', function(e) {
41659 // we fire even if inothing is selected..
41660 this.fireEvent('edit', this, this.lastData );
41670 initEvents : function(){
41671 Roo.form.ComboBox.superclass.initEvents.call(this);
41673 this.keyNav = new Roo.KeyNav(this.el, {
41674 "up" : function(e){
41675 this.inKeyMode = true;
41679 "down" : function(e){
41680 if(!this.isExpanded()){
41681 this.onTriggerClick();
41683 this.inKeyMode = true;
41688 "enter" : function(e){
41689 this.onViewClick();
41693 "esc" : function(e){
41697 "tab" : function(e){
41698 this.onViewClick(false);
41699 this.fireEvent("specialkey", this, e);
41705 doRelay : function(foo, bar, hname){
41706 if(hname == 'down' || this.scope.isExpanded()){
41707 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41714 this.queryDelay = Math.max(this.queryDelay || 10,
41715 this.mode == 'local' ? 10 : 250);
41716 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41717 if(this.typeAhead){
41718 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41720 if(this.editable !== false){
41721 this.el.on("keyup", this.onKeyUp, this);
41723 if(this.forceSelection){
41724 this.on('blur', this.doForce, this);
41728 onDestroy : function(){
41730 this.view.setStore(null);
41731 this.view.el.removeAllListeners();
41732 this.view.el.remove();
41733 this.view.purgeListeners();
41736 this.list.destroy();
41739 this.store.un('beforeload', this.onBeforeLoad, this);
41740 this.store.un('load', this.onLoad, this);
41741 this.store.un('loadexception', this.onLoadException, this);
41743 Roo.form.ComboBox.superclass.onDestroy.call(this);
41747 fireKey : function(e){
41748 if(e.isNavKeyPress() && !this.list.isVisible()){
41749 this.fireEvent("specialkey", this, e);
41754 onResize: function(w, h){
41755 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41757 if(typeof w != 'number'){
41758 // we do not handle it!?!?
41761 var tw = this.trigger.getWidth();
41762 tw += this.addicon ? this.addicon.getWidth() : 0;
41763 tw += this.editicon ? this.editicon.getWidth() : 0;
41765 this.el.setWidth( this.adjustWidth('input', x));
41767 this.trigger.setStyle('left', x+'px');
41769 if(this.list && this.listWidth === undefined){
41770 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41771 this.list.setWidth(lw);
41772 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41780 * Allow or prevent the user from directly editing the field text. If false is passed,
41781 * the user will only be able to select from the items defined in the dropdown list. This method
41782 * is the runtime equivalent of setting the 'editable' config option at config time.
41783 * @param {Boolean} value True to allow the user to directly edit the field text
41785 setEditable : function(value){
41786 if(value == this.editable){
41789 this.editable = value;
41791 this.el.dom.setAttribute('readOnly', true);
41792 this.el.on('mousedown', this.onTriggerClick, this);
41793 this.el.addClass('x-combo-noedit');
41795 this.el.dom.setAttribute('readOnly', false);
41796 this.el.un('mousedown', this.onTriggerClick, this);
41797 this.el.removeClass('x-combo-noedit');
41802 onBeforeLoad : function(){
41803 if(!this.hasFocus){
41806 this.innerList.update(this.loadingText ?
41807 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41808 this.restrictHeight();
41809 this.selectedIndex = -1;
41813 onLoad : function(){
41814 if(!this.hasFocus){
41817 if(this.store.getCount() > 0){
41819 this.restrictHeight();
41820 if(this.lastQuery == this.allQuery){
41822 this.el.dom.select();
41824 if(!this.selectByValue(this.value, true)){
41825 this.select(0, true);
41829 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41830 this.taTask.delay(this.typeAheadDelay);
41834 this.onEmptyResults();
41839 onLoadException : function()
41842 Roo.log(this.store.reader.jsonData);
41843 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41844 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41850 onTypeAhead : function(){
41851 if(this.store.getCount() > 0){
41852 var r = this.store.getAt(0);
41853 var newValue = r.data[this.displayField];
41854 var len = newValue.length;
41855 var selStart = this.getRawValue().length;
41856 if(selStart != len){
41857 this.setRawValue(newValue);
41858 this.selectText(selStart, newValue.length);
41864 onSelect : function(record, index){
41865 if(this.fireEvent('beforeselect', this, record, index) !== false){
41866 this.setFromData(index > -1 ? record.data : false);
41868 this.fireEvent('select', this, record, index);
41873 * Returns the currently selected field value or empty string if no value is set.
41874 * @return {String} value The selected value
41876 getValue : function(){
41877 if(this.valueField){
41878 return typeof this.value != 'undefined' ? this.value : '';
41880 return Roo.form.ComboBox.superclass.getValue.call(this);
41884 * Clears any text/value currently set in the field
41886 clearValue : function(){
41887 if(this.hiddenField){
41888 this.hiddenField.value = '';
41891 this.setRawValue('');
41892 this.lastSelectionText = '';
41897 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41898 * will be displayed in the field. If the value does not match the data value of an existing item,
41899 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41900 * Otherwise the field will be blank (although the value will still be set).
41901 * @param {String} value The value to match
41903 setValue : function(v){
41905 if(this.valueField){
41906 var r = this.findRecord(this.valueField, v);
41908 text = r.data[this.displayField];
41909 }else if(this.valueNotFoundText !== undefined){
41910 text = this.valueNotFoundText;
41913 this.lastSelectionText = text;
41914 if(this.hiddenField){
41915 this.hiddenField.value = v;
41917 Roo.form.ComboBox.superclass.setValue.call(this, text);
41921 * @property {Object} the last set data for the element
41926 * Sets the value of the field based on a object which is related to the record format for the store.
41927 * @param {Object} value the value to set as. or false on reset?
41929 setFromData : function(o){
41930 var dv = ''; // display value
41931 var vv = ''; // value value..
41933 if (this.displayField) {
41934 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41936 // this is an error condition!!!
41937 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41940 if(this.valueField){
41941 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41943 if(this.hiddenField){
41944 this.hiddenField.value = vv;
41946 this.lastSelectionText = dv;
41947 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41951 // no hidden field.. - we store the value in 'value', but still display
41952 // display field!!!!
41953 this.lastSelectionText = dv;
41954 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41960 reset : function(){
41961 // overridden so that last data is reset..
41962 this.setValue(this.resetValue);
41963 this.originalValue = this.getValue();
41964 this.clearInvalid();
41965 this.lastData = false;
41967 this.view.clearSelections();
41971 findRecord : function(prop, value){
41973 if(this.store.getCount() > 0){
41974 this.store.each(function(r){
41975 if(r.data[prop] == value){
41985 getName: function()
41987 // returns hidden if it's set..
41988 if (!this.rendered) {return ''};
41989 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41993 onViewMove : function(e, t){
41994 this.inKeyMode = false;
41998 onViewOver : function(e, t){
41999 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42002 var item = this.view.findItemFromChild(t);
42004 var index = this.view.indexOf(item);
42005 this.select(index, false);
42010 onViewClick : function(doFocus)
42012 var index = this.view.getSelectedIndexes()[0];
42013 var r = this.store.getAt(index);
42015 this.onSelect(r, index);
42017 if(doFocus !== false && !this.blockFocus){
42023 restrictHeight : function(){
42024 this.innerList.dom.style.height = '';
42025 var inner = this.innerList.dom;
42026 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42027 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42028 this.list.beginUpdate();
42029 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42030 this.list.alignTo(this.el, this.listAlign);
42031 this.list.endUpdate();
42035 onEmptyResults : function(){
42040 * Returns true if the dropdown list is expanded, else false.
42042 isExpanded : function(){
42043 return this.list.isVisible();
42047 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42048 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42049 * @param {String} value The data value of the item to select
42050 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42051 * selected item if it is not currently in view (defaults to true)
42052 * @return {Boolean} True if the value matched an item in the list, else false
42054 selectByValue : function(v, scrollIntoView){
42055 if(v !== undefined && v !== null){
42056 var r = this.findRecord(this.valueField || this.displayField, v);
42058 this.select(this.store.indexOf(r), scrollIntoView);
42066 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42067 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42068 * @param {Number} index The zero-based index of the list item to select
42069 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42070 * selected item if it is not currently in view (defaults to true)
42072 select : function(index, scrollIntoView){
42073 this.selectedIndex = index;
42074 this.view.select(index);
42075 if(scrollIntoView !== false){
42076 var el = this.view.getNode(index);
42078 this.innerList.scrollChildIntoView(el, false);
42084 selectNext : function(){
42085 var ct = this.store.getCount();
42087 if(this.selectedIndex == -1){
42089 }else if(this.selectedIndex < ct-1){
42090 this.select(this.selectedIndex+1);
42096 selectPrev : function(){
42097 var ct = this.store.getCount();
42099 if(this.selectedIndex == -1){
42101 }else if(this.selectedIndex != 0){
42102 this.select(this.selectedIndex-1);
42108 onKeyUp : function(e){
42109 if(this.editable !== false && !e.isSpecialKey()){
42110 this.lastKey = e.getKey();
42111 this.dqTask.delay(this.queryDelay);
42116 validateBlur : function(){
42117 return !this.list || !this.list.isVisible();
42121 initQuery : function(){
42122 this.doQuery(this.getRawValue());
42126 doForce : function(){
42127 if(this.el.dom.value.length > 0){
42128 this.el.dom.value =
42129 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42135 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42136 * query allowing the query action to be canceled if needed.
42137 * @param {String} query The SQL query to execute
42138 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42139 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42140 * saved in the current store (defaults to false)
42142 doQuery : function(q, forceAll){
42143 if(q === undefined || q === null){
42148 forceAll: forceAll,
42152 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42156 forceAll = qe.forceAll;
42157 if(forceAll === true || (q.length >= this.minChars)){
42158 if(this.lastQuery != q || this.alwaysQuery){
42159 this.lastQuery = q;
42160 if(this.mode == 'local'){
42161 this.selectedIndex = -1;
42163 this.store.clearFilter();
42165 this.store.filter(this.displayField, q);
42169 this.store.baseParams[this.queryParam] = q;
42171 params: this.getParams(q)
42176 this.selectedIndex = -1;
42183 getParams : function(q){
42185 //p[this.queryParam] = q;
42188 p.limit = this.pageSize;
42194 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42196 collapse : function(){
42197 if(!this.isExpanded()){
42201 Roo.get(document).un('mousedown', this.collapseIf, this);
42202 Roo.get(document).un('mousewheel', this.collapseIf, this);
42203 if (!this.editable) {
42204 Roo.get(document).un('keydown', this.listKeyPress, this);
42206 this.fireEvent('collapse', this);
42210 collapseIf : function(e){
42211 if(!e.within(this.wrap) && !e.within(this.list)){
42217 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42219 expand : function(){
42220 if(this.isExpanded() || !this.hasFocus){
42223 this.list.alignTo(this.el, this.listAlign);
42225 Roo.get(document).on('mousedown', this.collapseIf, this);
42226 Roo.get(document).on('mousewheel', this.collapseIf, this);
42227 if (!this.editable) {
42228 Roo.get(document).on('keydown', this.listKeyPress, this);
42231 this.fireEvent('expand', this);
42235 // Implements the default empty TriggerField.onTriggerClick function
42236 onTriggerClick : function(){
42240 if(this.isExpanded()){
42242 if (!this.blockFocus) {
42247 this.hasFocus = true;
42248 if(this.triggerAction == 'all') {
42249 this.doQuery(this.allQuery, true);
42251 this.doQuery(this.getRawValue());
42253 if (!this.blockFocus) {
42258 listKeyPress : function(e)
42260 //Roo.log('listkeypress');
42261 // scroll to first matching element based on key pres..
42262 if (e.isSpecialKey()) {
42265 var k = String.fromCharCode(e.getKey()).toUpperCase();
42268 var csel = this.view.getSelectedNodes();
42269 var cselitem = false;
42271 var ix = this.view.indexOf(csel[0]);
42272 cselitem = this.store.getAt(ix);
42273 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42279 this.store.each(function(v) {
42281 // start at existing selection.
42282 if (cselitem.id == v.id) {
42288 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42289 match = this.store.indexOf(v);
42294 if (match === false) {
42295 return true; // no more action?
42298 this.view.select(match);
42299 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42300 sn.scrollIntoView(sn.dom.parentNode, false);
42304 * @cfg {Boolean} grow
42308 * @cfg {Number} growMin
42312 * @cfg {Number} growMax
42320 * Copyright(c) 2010-2012, Roo J Solutions Limited
42327 * @class Roo.form.ComboBoxArray
42328 * @extends Roo.form.TextField
42329 * A facebook style adder... for lists of email / people / countries etc...
42330 * pick multiple items from a combo box, and shows each one.
42332 * Fred [x] Brian [x] [Pick another |v]
42335 * For this to work: it needs various extra information
42336 * - normal combo problay has
42338 * + displayField, valueField
42340 * For our purpose...
42343 * If we change from 'extends' to wrapping...
42350 * Create a new ComboBoxArray.
42351 * @param {Object} config Configuration options
42355 Roo.form.ComboBoxArray = function(config)
42359 * @event beforeremove
42360 * Fires before remove the value from the list
42361 * @param {Roo.form.ComboBoxArray} _self This combo box array
42362 * @param {Roo.form.ComboBoxArray.Item} item removed item
42364 'beforeremove' : true,
42367 * Fires when remove the value from the list
42368 * @param {Roo.form.ComboBoxArray} _self This combo box array
42369 * @param {Roo.form.ComboBoxArray.Item} item removed item
42376 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42378 this.items = new Roo.util.MixedCollection(false);
42380 // construct the child combo...
42390 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42393 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42398 // behavies liek a hiddne field
42399 inputType: 'hidden',
42401 * @cfg {Number} width The width of the box that displays the selected element
42408 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42412 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42414 hiddenName : false,
42416 * @cfg {String} seperator The value seperator normally ','
42420 // private the array of items that are displayed..
42422 // private - the hidden field el.
42424 // private - the filed el..
42427 //validateValue : function() { return true; }, // all values are ok!
42428 //onAddClick: function() { },
42430 onRender : function(ct, position)
42433 // create the standard hidden element
42434 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42437 // give fake names to child combo;
42438 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42439 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42441 this.combo = Roo.factory(this.combo, Roo.form);
42442 this.combo.onRender(ct, position);
42443 if (typeof(this.combo.width) != 'undefined') {
42444 this.combo.onResize(this.combo.width,0);
42447 this.combo.initEvents();
42449 // assigned so form know we need to do this..
42450 this.store = this.combo.store;
42451 this.valueField = this.combo.valueField;
42452 this.displayField = this.combo.displayField ;
42455 this.combo.wrap.addClass('x-cbarray-grp');
42457 var cbwrap = this.combo.wrap.createChild(
42458 {tag: 'div', cls: 'x-cbarray-cb'},
42463 this.hiddenEl = this.combo.wrap.createChild({
42464 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42466 this.el = this.combo.wrap.createChild({
42467 tag: 'input', type:'hidden' , name: this.name, value : ''
42469 // this.el.dom.removeAttribute("name");
42472 this.outerWrap = this.combo.wrap;
42473 this.wrap = cbwrap;
42475 this.outerWrap.setWidth(this.width);
42476 this.outerWrap.dom.removeChild(this.el.dom);
42478 this.wrap.dom.appendChild(this.el.dom);
42479 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42480 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42482 this.combo.trigger.setStyle('position','relative');
42483 this.combo.trigger.setStyle('left', '0px');
42484 this.combo.trigger.setStyle('top', '2px');
42486 this.combo.el.setStyle('vertical-align', 'text-bottom');
42488 //this.trigger.setStyle('vertical-align', 'top');
42490 // this should use the code from combo really... on('add' ....)
42494 this.adder = this.outerWrap.createChild(
42495 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42497 this.adder.on('click', function(e) {
42498 _t.fireEvent('adderclick', this, e);
42502 //this.adder.on('click', this.onAddClick, _t);
42505 this.combo.on('select', function(cb, rec, ix) {
42506 this.addItem(rec.data);
42509 cb.el.dom.value = '';
42510 //cb.lastData = rec.data;
42519 getName: function()
42521 // returns hidden if it's set..
42522 if (!this.rendered) {return ''};
42523 return this.hiddenName ? this.hiddenName : this.name;
42528 onResize: function(w, h){
42531 // not sure if this is needed..
42532 //this.combo.onResize(w,h);
42534 if(typeof w != 'number'){
42535 // we do not handle it!?!?
42538 var tw = this.combo.trigger.getWidth();
42539 tw += this.addicon ? this.addicon.getWidth() : 0;
42540 tw += this.editicon ? this.editicon.getWidth() : 0;
42542 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42544 this.combo.trigger.setStyle('left', '0px');
42546 if(this.list && this.listWidth === undefined){
42547 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42548 this.list.setWidth(lw);
42549 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42556 addItem: function(rec)
42558 var valueField = this.combo.valueField;
42559 var displayField = this.combo.displayField;
42561 if (this.items.indexOfKey(rec[valueField]) > -1) {
42562 //console.log("GOT " + rec.data.id);
42566 var x = new Roo.form.ComboBoxArray.Item({
42567 //id : rec[this.idField],
42569 displayField : displayField ,
42570 tipField : displayField ,
42574 this.items.add(rec[valueField],x);
42575 // add it before the element..
42576 this.updateHiddenEl();
42577 x.render(this.outerWrap, this.wrap.dom);
42578 // add the image handler..
42581 updateHiddenEl : function()
42584 if (!this.hiddenEl) {
42588 var idField = this.combo.valueField;
42590 this.items.each(function(f) {
42591 ar.push(f.data[idField]);
42593 this.hiddenEl.dom.value = ar.join(this.seperator);
42599 this.items.clear();
42601 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42605 this.el.dom.value = '';
42606 if (this.hiddenEl) {
42607 this.hiddenEl.dom.value = '';
42611 getValue: function()
42613 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42615 setValue: function(v) // not a valid action - must use addItems..
42620 if (this.store.isLocal && (typeof(v) == 'string')) {
42621 // then we can use the store to find the values..
42622 // comma seperated at present.. this needs to allow JSON based encoding..
42623 this.hiddenEl.value = v;
42625 Roo.each(v.split(this.seperator), function(k) {
42626 Roo.log("CHECK " + this.valueField + ',' + k);
42627 var li = this.store.query(this.valueField, k);
42632 add[this.valueField] = k;
42633 add[this.displayField] = li.item(0).data[this.displayField];
42639 if (typeof(v) == 'object' ) {
42640 // then let's assume it's an array of objects..
42641 Roo.each(v, function(l) {
42643 if (typeof(l) == 'string') {
42645 add[this.valueField] = l;
42646 add[this.displayField] = l
42655 setFromData: function(v)
42657 // this recieves an object, if setValues is called.
42659 this.el.dom.value = v[this.displayField];
42660 this.hiddenEl.dom.value = v[this.valueField];
42661 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42664 var kv = v[this.valueField];
42665 var dv = v[this.displayField];
42666 kv = typeof(kv) != 'string' ? '' : kv;
42667 dv = typeof(dv) != 'string' ? '' : dv;
42670 var keys = kv.split(this.seperator);
42671 var display = dv.split(this.seperator);
42672 for (var i = 0 ; i < keys.length; i++) {
42674 add[this.valueField] = keys[i];
42675 add[this.displayField] = display[i];
42683 * Validates the combox array value
42684 * @return {Boolean} True if the value is valid, else false
42686 validate : function(){
42687 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42688 this.clearInvalid();
42694 validateValue : function(value){
42695 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42703 isDirty : function() {
42704 if(this.disabled) {
42709 var d = Roo.decode(String(this.originalValue));
42711 return String(this.getValue()) !== String(this.originalValue);
42714 var originalValue = [];
42716 for (var i = 0; i < d.length; i++){
42717 originalValue.push(d[i][this.valueField]);
42720 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42729 * @class Roo.form.ComboBoxArray.Item
42730 * @extends Roo.BoxComponent
42731 * A selected item in the list
42732 * Fred [x] Brian [x] [Pick another |v]
42735 * Create a new item.
42736 * @param {Object} config Configuration options
42739 Roo.form.ComboBoxArray.Item = function(config) {
42740 config.id = Roo.id();
42741 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42744 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42747 displayField : false,
42751 defaultAutoCreate : {
42753 cls: 'x-cbarray-item',
42760 src : Roo.BLANK_IMAGE_URL ,
42768 onRender : function(ct, position)
42770 Roo.form.Field.superclass.onRender.call(this, ct, position);
42773 var cfg = this.getAutoCreate();
42774 this.el = ct.createChild(cfg, position);
42777 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42779 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42780 this.cb.renderer(this.data) :
42781 String.format('{0}',this.data[this.displayField]);
42784 this.el.child('div').dom.setAttribute('qtip',
42785 String.format('{0}',this.data[this.tipField])
42788 this.el.child('img').on('click', this.remove, this);
42792 remove : function()
42794 if(this.cb.disabled){
42798 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42799 this.cb.items.remove(this);
42800 this.el.child('img').un('click', this.remove, this);
42802 this.cb.updateHiddenEl();
42804 this.cb.fireEvent('remove', this.cb, this);
42809 * RooJS Library 1.1.1
42810 * Copyright(c) 2008-2011 Alan Knowles
42817 * @class Roo.form.ComboNested
42818 * @extends Roo.form.ComboBox
42819 * A combobox for that allows selection of nested items in a list,
42834 * Create a new ComboNested
42835 * @param {Object} config Configuration options
42837 Roo.form.ComboNested = function(config){
42838 Roo.form.ComboCheck.superclass.constructor.call(this, config);
42839 // should verify some data...
42841 // hiddenName = required..
42842 // displayField = required
42843 // valudField == required
42844 var req= [ 'hiddenName', 'displayField', 'valueField' ];
42846 Roo.each(req, function(e) {
42847 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
42848 throw "Roo.form.ComboNested : missing value for: " + e;
42855 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
42858 * @config {Number} max Number of columns to show
42863 list : null, // the outermost div..
42864 innerLists : null, // the
42868 loadingChildren : false,
42870 onRender : function(ct, position)
42872 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
42874 if(this.hiddenName){
42875 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42877 this.hiddenField.value =
42878 this.hiddenValue !== undefined ? this.hiddenValue :
42879 this.value !== undefined ? this.value : '';
42881 // prevent input submission
42882 this.el.dom.removeAttribute('name');
42888 this.el.dom.setAttribute('autocomplete', 'off');
42891 var cls = 'x-combo-list';
42893 this.list = new Roo.Layer({
42894 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
42897 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
42898 this.list.setWidth(lw);
42899 this.list.swallowEvent('mousewheel');
42900 this.assetHeight = 0;
42903 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
42904 this.assetHeight += this.header.getHeight();
42906 this.innerLists = [];
42909 for (var i =0 ; i < this.maxColumns; i++) {
42910 this.onRenderList( cls, i);
42913 // always needs footer, as we are going to have an 'OK' button.
42914 this.footer = this.list.createChild({cls:cls+'-ft'});
42915 this.pageTb = new Roo.Toolbar(this.footer);
42920 handler: function()
42926 if ( this.allowBlank && !this.disableClear) {
42928 this.pageTb.add(new Roo.Toolbar.Fill(), {
42929 cls: 'x-btn-icon x-btn-clear',
42931 handler: function()
42934 _this.clearValue();
42935 _this.onSelect(false, -1);
42940 this.assetHeight += this.footer.getHeight();
42944 onRenderList : function ( cls, i)
42947 var lw = Math.floor(
42948 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
42951 this.list.setWidth(lw); // default to '1'
42953 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
42954 //il.on('mouseover', this.onViewOver, this, { list: i });
42955 //il.on('mousemove', this.onViewMove, this, { list: i });
42957 il.setStyle({ 'overflow-x' : 'hidden'});
42960 this.tpl = new Roo.Template({
42961 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
42962 isEmpty: function (value, allValues) {
42964 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
42965 return dl ? 'has-children' : 'no-children'
42970 var store = this.store;
42972 store = new Roo.data.SimpleStore({
42973 //fields : this.store.reader.meta.fields,
42974 reader : this.store.reader,
42978 this.stores[i] = store;
42980 var view = this.views[i] = new Roo.View(
42986 selectedClass: this.selectedClass
42989 view.getEl().setWidth(lw);
42990 view.getEl().setStyle({
42991 position: i < 1 ? 'relative' : 'absolute',
42993 left: (i * lw ) + 'px',
42994 display : i > 0 ? 'none' : 'block'
42996 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
42997 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
42998 //view.on('click', this.onViewClick, this, { list : i });
43000 store.on('beforeload', this.onBeforeLoad, this);
43001 store.on('load', this.onLoad, this, { list : i});
43002 store.on('loadexception', this.onLoadException, this);
43004 // hide the other vies..
43010 restrictHeight : function()
43013 Roo.each(this.innerLists, function(il,i) {
43014 var el = this.views[i].getEl();
43015 el.dom.style.height = '';
43016 var inner = el.dom;
43017 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
43018 // only adjust heights on other ones..
43019 mh = Math.max(h, mh);
43022 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43023 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43030 this.list.beginUpdate();
43031 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43032 this.list.alignTo(this.el, this.listAlign);
43033 this.list.endUpdate();
43038 // -- store handlers..
43040 onBeforeLoad : function()
43042 if(!this.hasFocus){
43045 this.innerLists[0].update(this.loadingText ?
43046 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43047 this.restrictHeight();
43048 this.selectedIndex = -1;
43051 onLoad : function(a,b,c,d)
43053 if (!this.loadingChildren) {
43054 // then we are loading the top level. - hide the children
43055 for (var i = 1;i < this.views.length; i++) {
43056 this.views[i].getEl().setStyle({ display : 'none' });
43058 var lw = Math.floor(
43059 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43062 this.list.setWidth(lw); // default to '1'
43066 if(!this.hasFocus){
43070 if(this.store.getCount() > 0) {
43072 this.restrictHeight();
43074 this.onEmptyResults();
43077 if (!this.loadingChildren) {
43078 this.selectActive();
43081 this.stores[1].loadData([]);
43082 this.stores[2].loadData([]);
43091 onLoadException : function()
43094 Roo.log(this.store.reader.jsonData);
43095 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43096 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43101 // no cleaning of leading spaces on blur here.
43102 cleanLeadingSpace : function(e) { },
43105 onSelectChange : function (view, sels, opts )
43107 var ix = view.getSelectedIndexes();
43109 if (opts.list > this.maxColumns - 2) {
43110 if (view.store.getCount()< 1) {
43111 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43115 // used to clear ?? but if we are loading unselected
43116 this.setFromData(view.store.getAt(ix[0]).data);
43125 // this get's fired when trigger opens..
43126 // this.setFromData({});
43127 var str = this.stores[opts.list+1];
43128 str.data.clear(); // removeall wihtout the fire events..
43132 var rec = view.store.getAt(ix[0]);
43134 this.setFromData(rec.data);
43135 this.fireEvent('select', this, rec, ix[0]);
43137 var lw = Math.floor(
43139 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43140 ) / this.maxColumns
43142 this.loadingChildren = true;
43143 this.stores[opts.list+1].loadDataFromChildren( rec );
43144 this.loadingChildren = false;
43145 var dl = this.stores[opts.list+1]. getTotalCount();
43147 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43149 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43150 for (var i = opts.list+2; i < this.views.length;i++) {
43151 this.views[i].getEl().setStyle({ display : 'none' });
43154 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43155 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43157 if (this.isLoading) {
43158 // this.selectActive(opts.list);
43166 onDoubleClick : function()
43168 this.collapse(); //??
43176 recordToStack : function(store, prop, value, stack)
43178 var cstore = new Roo.data.SimpleStore({
43179 //fields : this.store.reader.meta.fields, // we need array reader.. for
43180 reader : this.store.reader,
43184 var record = false;
43186 if(store.getCount() < 1){
43189 store.each(function(r){
43190 if(r.data[prop] == value){
43195 if (r.data.cn && r.data.cn.length) {
43196 cstore.loadDataFromChildren( r);
43197 var cret = _this.recordToStack(cstore, prop, value, stack);
43198 if (cret !== false) {
43207 if (record == false) {
43210 stack.unshift(srec);
43215 * find the stack of stores that match our value.
43220 selectActive : function ()
43222 // if store is not loaded, then we will need to wait for that to happen first.
43224 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43225 for (var i = 0; i < stack.length; i++ ) {
43226 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43238 * Ext JS Library 1.1.1
43239 * Copyright(c) 2006-2007, Ext JS, LLC.
43241 * Originally Released Under LGPL - original licence link has changed is not relivant.
43244 * <script type="text/javascript">
43247 * @class Roo.form.Checkbox
43248 * @extends Roo.form.Field
43249 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43251 * Creates a new Checkbox
43252 * @param {Object} config Configuration options
43254 Roo.form.Checkbox = function(config){
43255 Roo.form.Checkbox.superclass.constructor.call(this, config);
43259 * Fires when the checkbox is checked or unchecked.
43260 * @param {Roo.form.Checkbox} this This checkbox
43261 * @param {Boolean} checked The new checked value
43267 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43269 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43271 focusClass : undefined,
43273 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43275 fieldClass: "x-form-field",
43277 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43281 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43282 * {tag: "input", type: "checkbox", autocomplete: "off"})
43284 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43286 * @cfg {String} boxLabel The text that appears beside the checkbox
43290 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43294 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43296 valueOff: '0', // value when not checked..
43298 actionMode : 'viewEl',
43301 itemCls : 'x-menu-check-item x-form-item',
43302 groupClass : 'x-menu-group-item',
43303 inputType : 'hidden',
43306 inSetChecked: false, // check that we are not calling self...
43308 inputElement: false, // real input element?
43309 basedOn: false, // ????
43311 isFormField: true, // not sure where this is needed!!!!
43313 onResize : function(){
43314 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43315 if(!this.boxLabel){
43316 this.el.alignTo(this.wrap, 'c-c');
43320 initEvents : function(){
43321 Roo.form.Checkbox.superclass.initEvents.call(this);
43322 this.el.on("click", this.onClick, this);
43323 this.el.on("change", this.onClick, this);
43327 getResizeEl : function(){
43331 getPositionEl : function(){
43336 onRender : function(ct, position){
43337 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43339 if(this.inputValue !== undefined){
43340 this.el.dom.value = this.inputValue;
43343 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43344 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43345 var viewEl = this.wrap.createChild({
43346 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43347 this.viewEl = viewEl;
43348 this.wrap.on('click', this.onClick, this);
43350 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43351 this.el.on('propertychange', this.setFromHidden, this); //ie
43356 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43357 // viewEl.on('click', this.onClick, this);
43359 //if(this.checked){
43360 this.setChecked(this.checked);
43362 //this.checked = this.el.dom;
43368 initValue : Roo.emptyFn,
43371 * Returns the checked state of the checkbox.
43372 * @return {Boolean} True if checked, else false
43374 getValue : function(){
43376 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43378 return this.valueOff;
43383 onClick : function(){
43384 if (this.disabled) {
43387 this.setChecked(!this.checked);
43389 //if(this.el.dom.checked != this.checked){
43390 // this.setValue(this.el.dom.checked);
43395 * Sets the checked state of the checkbox.
43396 * On is always based on a string comparison between inputValue and the param.
43397 * @param {Boolean/String} value - the value to set
43398 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43400 setValue : function(v,suppressEvent){
43403 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43404 //if(this.el && this.el.dom){
43405 // this.el.dom.checked = this.checked;
43406 // this.el.dom.defaultChecked = this.checked;
43408 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43409 //this.fireEvent("check", this, this.checked);
43412 setChecked : function(state,suppressEvent)
43414 if (this.inSetChecked) {
43415 this.checked = state;
43421 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43423 this.checked = state;
43424 if(suppressEvent !== true){
43425 this.fireEvent('check', this, state);
43427 this.inSetChecked = true;
43428 this.el.dom.value = state ? this.inputValue : this.valueOff;
43429 this.inSetChecked = false;
43432 // handle setting of hidden value by some other method!!?!?
43433 setFromHidden: function()
43438 //console.log("SET FROM HIDDEN");
43439 //alert('setFrom hidden');
43440 this.setValue(this.el.dom.value);
43443 onDestroy : function()
43446 Roo.get(this.viewEl).remove();
43449 Roo.form.Checkbox.superclass.onDestroy.call(this);
43452 setBoxLabel : function(str)
43454 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43459 * Ext JS Library 1.1.1
43460 * Copyright(c) 2006-2007, Ext JS, LLC.
43462 * Originally Released Under LGPL - original licence link has changed is not relivant.
43465 * <script type="text/javascript">
43469 * @class Roo.form.Radio
43470 * @extends Roo.form.Checkbox
43471 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43472 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43474 * Creates a new Radio
43475 * @param {Object} config Configuration options
43477 Roo.form.Radio = function(){
43478 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43480 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43481 inputType: 'radio',
43484 * If this radio is part of a group, it will return the selected value
43487 getGroupValue : function(){
43488 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43492 onRender : function(ct, position){
43493 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43495 if(this.inputValue !== undefined){
43496 this.el.dom.value = this.inputValue;
43499 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43500 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43501 //var viewEl = this.wrap.createChild({
43502 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43503 //this.viewEl = viewEl;
43504 //this.wrap.on('click', this.onClick, this);
43506 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43507 //this.el.on('propertychange', this.setFromHidden, this); //ie
43512 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43513 // viewEl.on('click', this.onClick, this);
43516 this.el.dom.checked = 'checked' ;
43522 });//<script type="text/javascript">
43525 * Based Ext JS Library 1.1.1
43526 * Copyright(c) 2006-2007, Ext JS, LLC.
43532 * @class Roo.HtmlEditorCore
43533 * @extends Roo.Component
43534 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43536 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43539 Roo.HtmlEditorCore = function(config){
43542 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43547 * @event initialize
43548 * Fires when the editor is fully initialized (including the iframe)
43549 * @param {Roo.HtmlEditorCore} this
43554 * Fires when the editor is first receives the focus. Any insertion must wait
43555 * until after this event.
43556 * @param {Roo.HtmlEditorCore} this
43560 * @event beforesync
43561 * Fires before the textarea is updated with content from the editor iframe. Return false
43562 * to cancel the sync.
43563 * @param {Roo.HtmlEditorCore} this
43564 * @param {String} html
43568 * @event beforepush
43569 * Fires before the iframe editor is updated with content from the textarea. Return false
43570 * to cancel the push.
43571 * @param {Roo.HtmlEditorCore} this
43572 * @param {String} html
43577 * Fires when the textarea is updated with content from the editor iframe.
43578 * @param {Roo.HtmlEditorCore} this
43579 * @param {String} html
43584 * Fires when the iframe editor is updated with content from the textarea.
43585 * @param {Roo.HtmlEditorCore} this
43586 * @param {String} html
43591 * @event editorevent
43592 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43593 * @param {Roo.HtmlEditorCore} this
43599 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43601 // defaults : white / black...
43602 this.applyBlacklists();
43609 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43613 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43619 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43624 * @cfg {Number} height (in pixels)
43628 * @cfg {Number} width (in pixels)
43633 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43636 stylesheets: false,
43641 // private properties
43642 validationEvent : false,
43644 initialized : false,
43646 sourceEditMode : false,
43647 onFocus : Roo.emptyFn,
43649 hideMode:'offsets',
43653 // blacklist + whitelisted elements..
43660 * Protected method that will not generally be called directly. It
43661 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43662 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43664 getDocMarkup : function(){
43668 // inherit styels from page...??
43669 if (this.stylesheets === false) {
43671 Roo.get(document.head).select('style').each(function(node) {
43672 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43675 Roo.get(document.head).select('link').each(function(node) {
43676 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43679 } else if (!this.stylesheets.length) {
43681 st = '<style type="text/css">' +
43682 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43685 for (var i in this.stylesheets) {
43686 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43691 st += '<style type="text/css">' +
43692 'IMG { cursor: pointer } ' +
43695 var cls = 'roo-htmleditor-body';
43697 if(this.bodyCls.length){
43698 cls += ' ' + this.bodyCls;
43701 return '<html><head>' + st +
43702 //<style type="text/css">' +
43703 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43705 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43709 onRender : function(ct, position)
43712 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43713 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43716 this.el.dom.style.border = '0 none';
43717 this.el.dom.setAttribute('tabIndex', -1);
43718 this.el.addClass('x-hidden hide');
43722 if(Roo.isIE){ // fix IE 1px bogus margin
43723 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43727 this.frameId = Roo.id();
43731 var iframe = this.owner.wrap.createChild({
43733 cls: 'form-control', // bootstrap..
43735 name: this.frameId,
43736 frameBorder : 'no',
43737 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43742 this.iframe = iframe.dom;
43744 this.assignDocWin();
43746 this.doc.designMode = 'on';
43749 this.doc.write(this.getDocMarkup());
43753 var task = { // must defer to wait for browser to be ready
43755 //console.log("run task?" + this.doc.readyState);
43756 this.assignDocWin();
43757 if(this.doc.body || this.doc.readyState == 'complete'){
43759 this.doc.designMode="on";
43763 Roo.TaskMgr.stop(task);
43764 this.initEditor.defer(10, this);
43771 Roo.TaskMgr.start(task);
43776 onResize : function(w, h)
43778 Roo.log('resize: ' +w + ',' + h );
43779 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43783 if(typeof w == 'number'){
43785 this.iframe.style.width = w + 'px';
43787 if(typeof h == 'number'){
43789 this.iframe.style.height = h + 'px';
43791 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43798 * Toggles the editor between standard and source edit mode.
43799 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43801 toggleSourceEdit : function(sourceEditMode){
43803 this.sourceEditMode = sourceEditMode === true;
43805 if(this.sourceEditMode){
43807 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43810 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43811 //this.iframe.className = '';
43814 //this.setSize(this.owner.wrap.getSize());
43815 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43822 * Protected method that will not generally be called directly. If you need/want
43823 * custom HTML cleanup, this is the method you should override.
43824 * @param {String} html The HTML to be cleaned
43825 * return {String} The cleaned HTML
43827 cleanHtml : function(html){
43828 html = String(html);
43829 if(html.length > 5){
43830 if(Roo.isSafari){ // strip safari nonsense
43831 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43834 if(html == ' '){
43841 * HTML Editor -> Textarea
43842 * Protected method that will not generally be called directly. Syncs the contents
43843 * of the editor iframe with the textarea.
43845 syncValue : function(){
43846 if(this.initialized){
43847 var bd = (this.doc.body || this.doc.documentElement);
43848 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43849 var html = bd.innerHTML;
43851 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43852 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43854 html = '<div style="'+m[0]+'">' + html + '</div>';
43857 html = this.cleanHtml(html);
43858 // fix up the special chars.. normaly like back quotes in word...
43859 // however we do not want to do this with chinese..
43860 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
43862 var cc = match.charCodeAt();
43864 // Get the character value, handling surrogate pairs
43865 if (match.length == 2) {
43866 // It's a surrogate pair, calculate the Unicode code point
43867 var high = match.charCodeAt(0) - 0xD800;
43868 var low = match.charCodeAt(1) - 0xDC00;
43869 cc = (high * 0x400) + low + 0x10000;
43871 (cc >= 0x4E00 && cc < 0xA000 ) ||
43872 (cc >= 0x3400 && cc < 0x4E00 ) ||
43873 (cc >= 0xf900 && cc < 0xfb00 )
43878 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
43879 return "&#" + cc + ";";
43886 if(this.owner.fireEvent('beforesync', this, html) !== false){
43887 this.el.dom.value = html;
43888 this.owner.fireEvent('sync', this, html);
43894 * Protected method that will not generally be called directly. Pushes the value of the textarea
43895 * into the iframe editor.
43897 pushValue : function(){
43898 if(this.initialized){
43899 var v = this.el.dom.value.trim();
43901 // if(v.length < 1){
43905 if(this.owner.fireEvent('beforepush', this, v) !== false){
43906 var d = (this.doc.body || this.doc.documentElement);
43908 this.cleanUpPaste();
43909 this.el.dom.value = d.innerHTML;
43910 this.owner.fireEvent('push', this, v);
43916 deferFocus : function(){
43917 this.focus.defer(10, this);
43921 focus : function(){
43922 if(this.win && !this.sourceEditMode){
43929 assignDocWin: function()
43931 var iframe = this.iframe;
43934 this.doc = iframe.contentWindow.document;
43935 this.win = iframe.contentWindow;
43937 // if (!Roo.get(this.frameId)) {
43940 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43941 // this.win = Roo.get(this.frameId).dom.contentWindow;
43943 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43947 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43948 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43953 initEditor : function(){
43954 //console.log("INIT EDITOR");
43955 this.assignDocWin();
43959 this.doc.designMode="on";
43961 this.doc.write(this.getDocMarkup());
43964 var dbody = (this.doc.body || this.doc.documentElement);
43965 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43966 // this copies styles from the containing element into thsi one..
43967 // not sure why we need all of this..
43968 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43970 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43971 //ss['background-attachment'] = 'fixed'; // w3c
43972 dbody.bgProperties = 'fixed'; // ie
43973 //Roo.DomHelper.applyStyles(dbody, ss);
43974 Roo.EventManager.on(this.doc, {
43975 //'mousedown': this.onEditorEvent,
43976 'mouseup': this.onEditorEvent,
43977 'dblclick': this.onEditorEvent,
43978 'click': this.onEditorEvent,
43979 'keyup': this.onEditorEvent,
43984 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43986 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43987 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43989 this.initialized = true;
43991 this.owner.fireEvent('initialize', this);
43996 onDestroy : function(){
44002 //for (var i =0; i < this.toolbars.length;i++) {
44003 // // fixme - ask toolbars for heights?
44004 // this.toolbars[i].onDestroy();
44007 //this.wrap.dom.innerHTML = '';
44008 //this.wrap.remove();
44013 onFirstFocus : function(){
44015 this.assignDocWin();
44018 this.activated = true;
44021 if(Roo.isGecko){ // prevent silly gecko errors
44023 var s = this.win.getSelection();
44024 if(!s.focusNode || s.focusNode.nodeType != 3){
44025 var r = s.getRangeAt(0);
44026 r.selectNodeContents((this.doc.body || this.doc.documentElement));
44031 this.execCmd('useCSS', true);
44032 this.execCmd('styleWithCSS', false);
44035 this.owner.fireEvent('activate', this);
44039 adjustFont: function(btn){
44040 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44041 //if(Roo.isSafari){ // safari
44044 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44045 if(Roo.isSafari){ // safari
44046 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44047 v = (v < 10) ? 10 : v;
44048 v = (v > 48) ? 48 : v;
44049 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44054 v = Math.max(1, v+adjust);
44056 this.execCmd('FontSize', v );
44059 onEditorEvent : function(e)
44061 this.owner.fireEvent('editorevent', this, e);
44062 // this.updateToolbar();
44063 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44066 insertTag : function(tg)
44068 // could be a bit smarter... -> wrap the current selected tRoo..
44069 if (tg.toLowerCase() == 'span' ||
44070 tg.toLowerCase() == 'code' ||
44071 tg.toLowerCase() == 'sup' ||
44072 tg.toLowerCase() == 'sub'
44075 range = this.createRange(this.getSelection());
44076 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44077 wrappingNode.appendChild(range.extractContents());
44078 range.insertNode(wrappingNode);
44085 this.execCmd("formatblock", tg);
44089 insertText : function(txt)
44093 var range = this.createRange();
44094 range.deleteContents();
44095 //alert(Sender.getAttribute('label'));
44097 range.insertNode(this.doc.createTextNode(txt));
44103 * Executes a Midas editor command on the editor document and performs necessary focus and
44104 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44105 * @param {String} cmd The Midas command
44106 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44108 relayCmd : function(cmd, value){
44110 this.execCmd(cmd, value);
44111 this.owner.fireEvent('editorevent', this);
44112 //this.updateToolbar();
44113 this.owner.deferFocus();
44117 * Executes a Midas editor command directly on the editor document.
44118 * For visual commands, you should use {@link #relayCmd} instead.
44119 * <b>This should only be called after the editor is initialized.</b>
44120 * @param {String} cmd The Midas command
44121 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44123 execCmd : function(cmd, value){
44124 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44131 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44133 * @param {String} text | dom node..
44135 insertAtCursor : function(text)
44138 if(!this.activated){
44144 var r = this.doc.selection.createRange();
44155 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44159 // from jquery ui (MIT licenced)
44161 var win = this.win;
44163 if (win.getSelection && win.getSelection().getRangeAt) {
44164 range = win.getSelection().getRangeAt(0);
44165 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44166 range.insertNode(node);
44167 } else if (win.document.selection && win.document.selection.createRange) {
44168 // no firefox support
44169 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44170 win.document.selection.createRange().pasteHTML(txt);
44172 // no firefox support
44173 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44174 this.execCmd('InsertHTML', txt);
44183 mozKeyPress : function(e){
44185 var c = e.getCharCode(), cmd;
44188 c = String.fromCharCode(c).toLowerCase();
44202 this.cleanUpPaste.defer(100, this);
44210 e.preventDefault();
44218 fixKeys : function(){ // load time branching for fastest keydown performance
44220 return function(e){
44221 var k = e.getKey(), r;
44224 r = this.doc.selection.createRange();
44227 r.pasteHTML('    ');
44234 r = this.doc.selection.createRange();
44236 var target = r.parentElement();
44237 if(!target || target.tagName.toLowerCase() != 'li'){
44239 r.pasteHTML('<br />');
44245 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44246 this.cleanUpPaste.defer(100, this);
44252 }else if(Roo.isOpera){
44253 return function(e){
44254 var k = e.getKey();
44258 this.execCmd('InsertHTML','    ');
44261 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44262 this.cleanUpPaste.defer(100, this);
44267 }else if(Roo.isSafari){
44268 return function(e){
44269 var k = e.getKey();
44273 this.execCmd('InsertText','\t');
44277 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44278 this.cleanUpPaste.defer(100, this);
44286 getAllAncestors: function()
44288 var p = this.getSelectedNode();
44291 a.push(p); // push blank onto stack..
44292 p = this.getParentElement();
44296 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44300 a.push(this.doc.body);
44304 lastSelNode : false,
44307 getSelection : function()
44309 this.assignDocWin();
44310 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44313 getSelectedNode: function()
44315 // this may only work on Gecko!!!
44317 // should we cache this!!!!
44322 var range = this.createRange(this.getSelection()).cloneRange();
44325 var parent = range.parentElement();
44327 var testRange = range.duplicate();
44328 testRange.moveToElementText(parent);
44329 if (testRange.inRange(range)) {
44332 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44335 parent = parent.parentElement;
44340 // is ancestor a text element.
44341 var ac = range.commonAncestorContainer;
44342 if (ac.nodeType == 3) {
44343 ac = ac.parentNode;
44346 var ar = ac.childNodes;
44349 var other_nodes = [];
44350 var has_other_nodes = false;
44351 for (var i=0;i<ar.length;i++) {
44352 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44355 // fullly contained node.
44357 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44362 // probably selected..
44363 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44364 other_nodes.push(ar[i]);
44368 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44373 has_other_nodes = true;
44375 if (!nodes.length && other_nodes.length) {
44376 nodes= other_nodes;
44378 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44384 createRange: function(sel)
44386 // this has strange effects when using with
44387 // top toolbar - not sure if it's a great idea.
44388 //this.editor.contentWindow.focus();
44389 if (typeof sel != "undefined") {
44391 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44393 return this.doc.createRange();
44396 return this.doc.createRange();
44399 getParentElement: function()
44402 this.assignDocWin();
44403 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44405 var range = this.createRange(sel);
44408 var p = range.commonAncestorContainer;
44409 while (p.nodeType == 3) { // text node
44420 * Range intersection.. the hard stuff...
44424 * [ -- selected range --- ]
44428 * if end is before start or hits it. fail.
44429 * if start is after end or hits it fail.
44431 * if either hits (but other is outside. - then it's not
44437 // @see http://www.thismuchiknow.co.uk/?p=64.
44438 rangeIntersectsNode : function(range, node)
44440 var nodeRange = node.ownerDocument.createRange();
44442 nodeRange.selectNode(node);
44444 nodeRange.selectNodeContents(node);
44447 var rangeStartRange = range.cloneRange();
44448 rangeStartRange.collapse(true);
44450 var rangeEndRange = range.cloneRange();
44451 rangeEndRange.collapse(false);
44453 var nodeStartRange = nodeRange.cloneRange();
44454 nodeStartRange.collapse(true);
44456 var nodeEndRange = nodeRange.cloneRange();
44457 nodeEndRange.collapse(false);
44459 return rangeStartRange.compareBoundaryPoints(
44460 Range.START_TO_START, nodeEndRange) == -1 &&
44461 rangeEndRange.compareBoundaryPoints(
44462 Range.START_TO_START, nodeStartRange) == 1;
44466 rangeCompareNode : function(range, node)
44468 var nodeRange = node.ownerDocument.createRange();
44470 nodeRange.selectNode(node);
44472 nodeRange.selectNodeContents(node);
44476 range.collapse(true);
44478 nodeRange.collapse(true);
44480 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44481 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44483 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44485 var nodeIsBefore = ss == 1;
44486 var nodeIsAfter = ee == -1;
44488 if (nodeIsBefore && nodeIsAfter) {
44491 if (!nodeIsBefore && nodeIsAfter) {
44492 return 1; //right trailed.
44495 if (nodeIsBefore && !nodeIsAfter) {
44496 return 2; // left trailed.
44502 // private? - in a new class?
44503 cleanUpPaste : function()
44505 // cleans up the whole document..
44506 Roo.log('cleanuppaste');
44508 this.cleanUpChildren(this.doc.body);
44509 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44510 if (clean != this.doc.body.innerHTML) {
44511 this.doc.body.innerHTML = clean;
44516 cleanWordChars : function(input) {// change the chars to hex code
44517 var he = Roo.HtmlEditorCore;
44519 var output = input;
44520 Roo.each(he.swapCodes, function(sw) {
44521 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44523 output = output.replace(swapper, sw[1]);
44530 cleanUpChildren : function (n)
44532 if (!n.childNodes.length) {
44535 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44536 this.cleanUpChild(n.childNodes[i]);
44543 cleanUpChild : function (node)
44546 //console.log(node);
44547 if (node.nodeName == "#text") {
44548 // clean up silly Windows -- stuff?
44551 if (node.nodeName == "#comment") {
44552 node.parentNode.removeChild(node);
44553 // clean up silly Windows -- stuff?
44556 var lcname = node.tagName.toLowerCase();
44557 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44558 // whitelist of tags..
44560 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44562 node.parentNode.removeChild(node);
44567 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44569 // spans with no attributes - just remove them..
44570 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44571 remove_keep_children = true;
44574 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44575 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44577 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44578 // remove_keep_children = true;
44581 if (remove_keep_children) {
44582 this.cleanUpChildren(node);
44583 // inserts everything just before this node...
44584 while (node.childNodes.length) {
44585 var cn = node.childNodes[0];
44586 node.removeChild(cn);
44587 node.parentNode.insertBefore(cn, node);
44589 node.parentNode.removeChild(node);
44593 if (!node.attributes || !node.attributes.length) {
44598 this.cleanUpChildren(node);
44602 function cleanAttr(n,v)
44605 if (v.match(/^\./) || v.match(/^\//)) {
44608 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44611 if (v.match(/^#/)) {
44614 if (v.match(/^\{/)) { // allow template editing.
44617 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44618 node.removeAttribute(n);
44622 var cwhite = this.cwhite;
44623 var cblack = this.cblack;
44625 function cleanStyle(n,v)
44627 if (v.match(/expression/)) { //XSS?? should we even bother..
44628 node.removeAttribute(n);
44632 var parts = v.split(/;/);
44635 Roo.each(parts, function(p) {
44636 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44640 var l = p.split(':').shift().replace(/\s+/g,'');
44641 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44643 if ( cwhite.length && cblack.indexOf(l) > -1) {
44644 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44645 //node.removeAttribute(n);
44649 // only allow 'c whitelisted system attributes'
44650 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44651 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44652 //node.removeAttribute(n);
44662 if (clean.length) {
44663 node.setAttribute(n, clean.join(';'));
44665 node.removeAttribute(n);
44671 for (var i = node.attributes.length-1; i > -1 ; i--) {
44672 var a = node.attributes[i];
44675 if (a.name.toLowerCase().substr(0,2)=='on') {
44676 node.removeAttribute(a.name);
44679 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44680 node.removeAttribute(a.name);
44683 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44684 cleanAttr(a.name,a.value); // fixme..
44687 if (a.name == 'style') {
44688 cleanStyle(a.name,a.value);
44691 /// clean up MS crap..
44692 // tecnically this should be a list of valid class'es..
44695 if (a.name == 'class') {
44696 if (a.value.match(/^Mso/)) {
44697 node.removeAttribute('class');
44700 if (a.value.match(/^body$/)) {
44701 node.removeAttribute('class');
44712 this.cleanUpChildren(node);
44718 * Clean up MS wordisms...
44720 cleanWord : function(node)
44723 this.cleanWord(this.doc.body);
44728 node.nodeName == 'SPAN' &&
44729 !node.hasAttributes() &&
44730 node.childNodes.length == 1 &&
44731 node.firstChild.nodeName == "#text"
44733 var textNode = node.firstChild;
44734 node.removeChild(textNode);
44735 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44736 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44738 node.parentNode.insertBefore(textNode, node);
44739 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44740 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44742 node.parentNode.removeChild(node);
44745 if (node.nodeName == "#text") {
44746 // clean up silly Windows -- stuff?
44749 if (node.nodeName == "#comment") {
44750 node.parentNode.removeChild(node);
44751 // clean up silly Windows -- stuff?
44755 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44756 node.parentNode.removeChild(node);
44759 //Roo.log(node.tagName);
44760 // remove - but keep children..
44761 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44762 //Roo.log('-- removed');
44763 while (node.childNodes.length) {
44764 var cn = node.childNodes[0];
44765 node.removeChild(cn);
44766 node.parentNode.insertBefore(cn, node);
44767 // move node to parent - and clean it..
44768 this.cleanWord(cn);
44770 node.parentNode.removeChild(node);
44771 /// no need to iterate chidlren = it's got none..
44772 //this.iterateChildren(node, this.cleanWord);
44776 if (node.className.length) {
44778 var cn = node.className.split(/\W+/);
44780 Roo.each(cn, function(cls) {
44781 if (cls.match(/Mso[a-zA-Z]+/)) {
44786 node.className = cna.length ? cna.join(' ') : '';
44788 node.removeAttribute("class");
44792 if (node.hasAttribute("lang")) {
44793 node.removeAttribute("lang");
44796 if (node.hasAttribute("style")) {
44798 var styles = node.getAttribute("style").split(";");
44800 Roo.each(styles, function(s) {
44801 if (!s.match(/:/)) {
44804 var kv = s.split(":");
44805 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44808 // what ever is left... we allow.
44811 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44812 if (!nstyle.length) {
44813 node.removeAttribute('style');
44816 this.iterateChildren(node, this.cleanWord);
44822 * iterateChildren of a Node, calling fn each time, using this as the scole..
44823 * @param {DomNode} node node to iterate children of.
44824 * @param {Function} fn method of this class to call on each item.
44826 iterateChildren : function(node, fn)
44828 if (!node.childNodes.length) {
44831 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44832 fn.call(this, node.childNodes[i])
44838 * cleanTableWidths.
44840 * Quite often pasting from word etc.. results in tables with column and widths.
44841 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44844 cleanTableWidths : function(node)
44849 this.cleanTableWidths(this.doc.body);
44854 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44857 Roo.log(node.tagName);
44858 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44859 this.iterateChildren(node, this.cleanTableWidths);
44862 if (node.hasAttribute('width')) {
44863 node.removeAttribute('width');
44867 if (node.hasAttribute("style")) {
44870 var styles = node.getAttribute("style").split(";");
44872 Roo.each(styles, function(s) {
44873 if (!s.match(/:/)) {
44876 var kv = s.split(":");
44877 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44880 // what ever is left... we allow.
44883 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44884 if (!nstyle.length) {
44885 node.removeAttribute('style');
44889 this.iterateChildren(node, this.cleanTableWidths);
44897 domToHTML : function(currentElement, depth, nopadtext) {
44899 depth = depth || 0;
44900 nopadtext = nopadtext || false;
44902 if (!currentElement) {
44903 return this.domToHTML(this.doc.body);
44906 //Roo.log(currentElement);
44908 var allText = false;
44909 var nodeName = currentElement.nodeName;
44910 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44912 if (nodeName == '#text') {
44914 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44919 if (nodeName != 'BODY') {
44922 // Prints the node tagName, such as <A>, <IMG>, etc
44925 for(i = 0; i < currentElement.attributes.length;i++) {
44927 var aname = currentElement.attributes.item(i).name;
44928 if (!currentElement.attributes.item(i).value.length) {
44931 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44934 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44943 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44946 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44951 // Traverse the tree
44953 var currentElementChild = currentElement.childNodes.item(i);
44954 var allText = true;
44955 var innerHTML = '';
44957 while (currentElementChild) {
44958 // Formatting code (indent the tree so it looks nice on the screen)
44959 var nopad = nopadtext;
44960 if (lastnode == 'SPAN') {
44964 if (currentElementChild.nodeName == '#text') {
44965 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44966 toadd = nopadtext ? toadd : toadd.trim();
44967 if (!nopad && toadd.length > 80) {
44968 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44970 innerHTML += toadd;
44973 currentElementChild = currentElement.childNodes.item(i);
44979 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44981 // Recursively traverse the tree structure of the child node
44982 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44983 lastnode = currentElementChild.nodeName;
44985 currentElementChild=currentElement.childNodes.item(i);
44991 // The remaining code is mostly for formatting the tree
44992 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44997 ret+= "</"+tagName+">";
45003 applyBlacklists : function()
45005 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
45006 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
45010 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
45011 if (b.indexOf(tag) > -1) {
45014 this.white.push(tag);
45018 Roo.each(w, function(tag) {
45019 if (b.indexOf(tag) > -1) {
45022 if (this.white.indexOf(tag) > -1) {
45025 this.white.push(tag);
45030 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
45031 if (w.indexOf(tag) > -1) {
45034 this.black.push(tag);
45038 Roo.each(b, function(tag) {
45039 if (w.indexOf(tag) > -1) {
45042 if (this.black.indexOf(tag) > -1) {
45045 this.black.push(tag);
45050 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45051 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45055 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45056 if (b.indexOf(tag) > -1) {
45059 this.cwhite.push(tag);
45063 Roo.each(w, function(tag) {
45064 if (b.indexOf(tag) > -1) {
45067 if (this.cwhite.indexOf(tag) > -1) {
45070 this.cwhite.push(tag);
45075 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45076 if (w.indexOf(tag) > -1) {
45079 this.cblack.push(tag);
45083 Roo.each(b, function(tag) {
45084 if (w.indexOf(tag) > -1) {
45087 if (this.cblack.indexOf(tag) > -1) {
45090 this.cblack.push(tag);
45095 setStylesheets : function(stylesheets)
45097 if(typeof(stylesheets) == 'string'){
45098 Roo.get(this.iframe.contentDocument.head).createChild({
45100 rel : 'stylesheet',
45109 Roo.each(stylesheets, function(s) {
45114 Roo.get(_this.iframe.contentDocument.head).createChild({
45116 rel : 'stylesheet',
45125 removeStylesheets : function()
45129 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45134 setStyle : function(style)
45136 Roo.get(this.iframe.contentDocument.head).createChild({
45145 // hide stuff that is not compatible
45159 * @event specialkey
45163 * @cfg {String} fieldClass @hide
45166 * @cfg {String} focusClass @hide
45169 * @cfg {String} autoCreate @hide
45172 * @cfg {String} inputType @hide
45175 * @cfg {String} invalidClass @hide
45178 * @cfg {String} invalidText @hide
45181 * @cfg {String} msgFx @hide
45184 * @cfg {String} validateOnBlur @hide
45188 Roo.HtmlEditorCore.white = [
45189 'area', 'br', 'img', 'input', 'hr', 'wbr',
45191 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45192 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45193 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45194 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45195 'table', 'ul', 'xmp',
45197 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45200 'dir', 'menu', 'ol', 'ul', 'dl',
45206 Roo.HtmlEditorCore.black = [
45207 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45209 'base', 'basefont', 'bgsound', 'blink', 'body',
45210 'frame', 'frameset', 'head', 'html', 'ilayer',
45211 'iframe', 'layer', 'link', 'meta', 'object',
45212 'script', 'style' ,'title', 'xml' // clean later..
45214 Roo.HtmlEditorCore.clean = [
45215 'script', 'style', 'title', 'xml'
45217 Roo.HtmlEditorCore.remove = [
45222 Roo.HtmlEditorCore.ablack = [
45226 Roo.HtmlEditorCore.aclean = [
45227 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45231 Roo.HtmlEditorCore.pwhite= [
45232 'http', 'https', 'mailto'
45235 // white listed style attributes.
45236 Roo.HtmlEditorCore.cwhite= [
45237 // 'text-align', /// default is to allow most things..
45243 // black listed style attributes.
45244 Roo.HtmlEditorCore.cblack= [
45245 // 'font-size' -- this can be set by the project
45249 Roo.HtmlEditorCore.swapCodes =[
45250 [ 8211, "–" ],
45251 [ 8212, "—" ],
45260 //<script type="text/javascript">
45263 * Ext JS Library 1.1.1
45264 * Copyright(c) 2006-2007, Ext JS, LLC.
45270 Roo.form.HtmlEditor = function(config){
45274 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45276 if (!this.toolbars) {
45277 this.toolbars = [];
45279 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45285 * @class Roo.form.HtmlEditor
45286 * @extends Roo.form.Field
45287 * Provides a lightweight HTML Editor component.
45289 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45291 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45292 * supported by this editor.</b><br/><br/>
45293 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45294 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45296 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45298 * @cfg {Boolean} clearUp
45302 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45307 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45312 * @cfg {Number} height (in pixels)
45316 * @cfg {Number} width (in pixels)
45321 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45324 stylesheets: false,
45328 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45333 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45339 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45344 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45352 // private properties
45353 validationEvent : false,
45355 initialized : false,
45358 onFocus : Roo.emptyFn,
45360 hideMode:'offsets',
45362 actionMode : 'container', // defaults to hiding it...
45364 defaultAutoCreate : { // modified by initCompnoent..
45366 style:"width:500px;height:300px;",
45367 autocomplete: "new-password"
45371 initComponent : function(){
45374 * @event initialize
45375 * Fires when the editor is fully initialized (including the iframe)
45376 * @param {HtmlEditor} this
45381 * Fires when the editor is first receives the focus. Any insertion must wait
45382 * until after this event.
45383 * @param {HtmlEditor} this
45387 * @event beforesync
45388 * Fires before the textarea is updated with content from the editor iframe. Return false
45389 * to cancel the sync.
45390 * @param {HtmlEditor} this
45391 * @param {String} html
45395 * @event beforepush
45396 * Fires before the iframe editor is updated with content from the textarea. Return false
45397 * to cancel the push.
45398 * @param {HtmlEditor} this
45399 * @param {String} html
45404 * Fires when the textarea is updated with content from the editor iframe.
45405 * @param {HtmlEditor} this
45406 * @param {String} html
45411 * Fires when the iframe editor is updated with content from the textarea.
45412 * @param {HtmlEditor} this
45413 * @param {String} html
45417 * @event editmodechange
45418 * Fires when the editor switches edit modes
45419 * @param {HtmlEditor} this
45420 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45422 editmodechange: true,
45424 * @event editorevent
45425 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45426 * @param {HtmlEditor} this
45430 * @event firstfocus
45431 * Fires when on first focus - needed by toolbars..
45432 * @param {HtmlEditor} this
45437 * Auto save the htmlEditor value as a file into Events
45438 * @param {HtmlEditor} this
45442 * @event savedpreview
45443 * preview the saved version of htmlEditor
45444 * @param {HtmlEditor} this
45446 savedpreview: true,
45449 * @event stylesheetsclick
45450 * Fires when press the Sytlesheets button
45451 * @param {Roo.HtmlEditorCore} this
45453 stylesheetsclick: true
45455 this.defaultAutoCreate = {
45457 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45458 autocomplete: "new-password"
45463 * Protected method that will not generally be called directly. It
45464 * is called when the editor creates its toolbar. Override this method if you need to
45465 * add custom toolbar buttons.
45466 * @param {HtmlEditor} editor
45468 createToolbar : function(editor){
45469 Roo.log("create toolbars");
45470 if (!editor.toolbars || !editor.toolbars.length) {
45471 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45474 for (var i =0 ; i < editor.toolbars.length;i++) {
45475 editor.toolbars[i] = Roo.factory(
45476 typeof(editor.toolbars[i]) == 'string' ?
45477 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45478 Roo.form.HtmlEditor);
45479 editor.toolbars[i].init(editor);
45487 onRender : function(ct, position)
45490 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45492 this.wrap = this.el.wrap({
45493 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45496 this.editorcore.onRender(ct, position);
45498 if (this.resizable) {
45499 this.resizeEl = new Roo.Resizable(this.wrap, {
45503 minHeight : this.height,
45504 height: this.height,
45505 handles : this.resizable,
45508 resize : function(r, w, h) {
45509 _t.onResize(w,h); // -something
45515 this.createToolbar(this);
45519 this.setSize(this.wrap.getSize());
45521 if (this.resizeEl) {
45522 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45523 // should trigger onReize..
45526 this.keyNav = new Roo.KeyNav(this.el, {
45528 "tab" : function(e){
45529 e.preventDefault();
45531 var value = this.getValue();
45533 var start = this.el.dom.selectionStart;
45534 var end = this.el.dom.selectionEnd;
45538 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45539 this.el.dom.setSelectionRange(end + 1, end + 1);
45543 var f = value.substring(0, start).split("\t");
45545 if(f.pop().length != 0){
45549 this.setValue(f.join("\t") + value.substring(end));
45550 this.el.dom.setSelectionRange(start - 1, start - 1);
45554 "home" : function(e){
45555 e.preventDefault();
45557 var curr = this.el.dom.selectionStart;
45558 var lines = this.getValue().split("\n");
45565 this.el.dom.setSelectionRange(0, 0);
45571 for (var i = 0; i < lines.length;i++) {
45572 pos += lines[i].length;
45582 pos -= lines[i].length;
45588 this.el.dom.setSelectionRange(pos, pos);
45592 this.el.dom.selectionStart = pos;
45593 this.el.dom.selectionEnd = curr;
45596 "end" : function(e){
45597 e.preventDefault();
45599 var curr = this.el.dom.selectionStart;
45600 var lines = this.getValue().split("\n");
45607 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45613 for (var i = 0; i < lines.length;i++) {
45615 pos += lines[i].length;
45629 this.el.dom.setSelectionRange(pos, pos);
45633 this.el.dom.selectionStart = curr;
45634 this.el.dom.selectionEnd = pos;
45639 doRelay : function(foo, bar, hname){
45640 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45646 // if(this.autosave && this.w){
45647 // this.autoSaveFn = setInterval(this.autosave, 1000);
45652 onResize : function(w, h)
45654 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45659 if(typeof w == 'number'){
45660 var aw = w - this.wrap.getFrameWidth('lr');
45661 this.el.setWidth(this.adjustWidth('textarea', aw));
45664 if(typeof h == 'number'){
45666 for (var i =0; i < this.toolbars.length;i++) {
45667 // fixme - ask toolbars for heights?
45668 tbh += this.toolbars[i].tb.el.getHeight();
45669 if (this.toolbars[i].footer) {
45670 tbh += this.toolbars[i].footer.el.getHeight();
45677 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45678 ah -= 5; // knock a few pixes off for look..
45680 this.el.setHeight(this.adjustWidth('textarea', ah));
45684 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45685 this.editorcore.onResize(ew,eh);
45690 * Toggles the editor between standard and source edit mode.
45691 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45693 toggleSourceEdit : function(sourceEditMode)
45695 this.editorcore.toggleSourceEdit(sourceEditMode);
45697 if(this.editorcore.sourceEditMode){
45698 Roo.log('editor - showing textarea');
45701 // Roo.log(this.syncValue());
45702 this.editorcore.syncValue();
45703 this.el.removeClass('x-hidden');
45704 this.el.dom.removeAttribute('tabIndex');
45707 for (var i = 0; i < this.toolbars.length; i++) {
45708 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45709 this.toolbars[i].tb.hide();
45710 this.toolbars[i].footer.hide();
45715 Roo.log('editor - hiding textarea');
45717 // Roo.log(this.pushValue());
45718 this.editorcore.pushValue();
45720 this.el.addClass('x-hidden');
45721 this.el.dom.setAttribute('tabIndex', -1);
45723 for (var i = 0; i < this.toolbars.length; i++) {
45724 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45725 this.toolbars[i].tb.show();
45726 this.toolbars[i].footer.show();
45730 //this.deferFocus();
45733 this.setSize(this.wrap.getSize());
45734 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45736 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45739 // private (for BoxComponent)
45740 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45742 // private (for BoxComponent)
45743 getResizeEl : function(){
45747 // private (for BoxComponent)
45748 getPositionEl : function(){
45753 initEvents : function(){
45754 this.originalValue = this.getValue();
45758 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45761 markInvalid : Roo.emptyFn,
45763 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45766 clearInvalid : Roo.emptyFn,
45768 setValue : function(v){
45769 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45770 this.editorcore.pushValue();
45775 deferFocus : function(){
45776 this.focus.defer(10, this);
45780 focus : function(){
45781 this.editorcore.focus();
45787 onDestroy : function(){
45793 for (var i =0; i < this.toolbars.length;i++) {
45794 // fixme - ask toolbars for heights?
45795 this.toolbars[i].onDestroy();
45798 this.wrap.dom.innerHTML = '';
45799 this.wrap.remove();
45804 onFirstFocus : function(){
45805 //Roo.log("onFirstFocus");
45806 this.editorcore.onFirstFocus();
45807 for (var i =0; i < this.toolbars.length;i++) {
45808 this.toolbars[i].onFirstFocus();
45814 syncValue : function()
45816 this.editorcore.syncValue();
45819 pushValue : function()
45821 this.editorcore.pushValue();
45824 setStylesheets : function(stylesheets)
45826 this.editorcore.setStylesheets(stylesheets);
45829 removeStylesheets : function()
45831 this.editorcore.removeStylesheets();
45835 // hide stuff that is not compatible
45849 * @event specialkey
45853 * @cfg {String} fieldClass @hide
45856 * @cfg {String} focusClass @hide
45859 * @cfg {String} autoCreate @hide
45862 * @cfg {String} inputType @hide
45865 * @cfg {String} invalidClass @hide
45868 * @cfg {String} invalidText @hide
45871 * @cfg {String} msgFx @hide
45874 * @cfg {String} validateOnBlur @hide
45878 // <script type="text/javascript">
45881 * Ext JS Library 1.1.1
45882 * Copyright(c) 2006-2007, Ext JS, LLC.
45888 * @class Roo.form.HtmlEditorToolbar1
45893 new Roo.form.HtmlEditor({
45896 new Roo.form.HtmlEditorToolbar1({
45897 disable : { fonts: 1 , format: 1, ..., ... , ...],
45903 * @cfg {Object} disable List of elements to disable..
45904 * @cfg {Array} btns List of additional buttons.
45908 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45911 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45914 Roo.apply(this, config);
45916 // default disabled, based on 'good practice'..
45917 this.disable = this.disable || {};
45918 Roo.applyIf(this.disable, {
45921 specialElements : true
45925 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45926 // dont call parent... till later.
45929 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45936 editorcore : false,
45938 * @cfg {Object} disable List of toolbar elements to disable
45945 * @cfg {String} createLinkText The default text for the create link prompt
45947 createLinkText : 'Please enter the URL for the link:',
45949 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45951 defaultLinkValue : 'http:/'+'/',
45955 * @cfg {Array} fontFamilies An array of available font families
45973 // "á" , ?? a acute?
45978 "°" // , // degrees
45980 // "é" , // e ecute
45981 // "ú" , // u ecute?
45984 specialElements : [
45986 text: "Insert Table",
45989 ihtml : '<table><tr><td>Cell</td></tr></table>'
45993 text: "Insert Image",
45996 ihtml : '<img src="about:blank"/>'
46005 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
46006 "input:submit", "input:button", "select", "textarea", "label" ],
46009 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
46011 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
46020 * @cfg {String} defaultFont default font to use.
46022 defaultFont: 'tahoma',
46024 fontSelect : false,
46027 formatCombo : false,
46029 init : function(editor)
46031 this.editor = editor;
46032 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46033 var editorcore = this.editorcore;
46037 var fid = editorcore.frameId;
46039 function btn(id, toggle, handler){
46040 var xid = fid + '-'+ id ;
46044 cls : 'x-btn-icon x-edit-'+id,
46045 enableToggle:toggle !== false,
46046 scope: _t, // was editor...
46047 handler:handler||_t.relayBtnCmd,
46048 clickEvent:'mousedown',
46049 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46056 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46058 // stop form submits
46059 tb.el.on('click', function(e){
46060 e.preventDefault(); // what does this do?
46063 if(!this.disable.font) { // && !Roo.isSafari){
46064 /* why no safari for fonts
46065 editor.fontSelect = tb.el.createChild({
46068 cls:'x-font-select',
46069 html: this.createFontOptions()
46072 editor.fontSelect.on('change', function(){
46073 var font = editor.fontSelect.dom.value;
46074 editor.relayCmd('fontname', font);
46075 editor.deferFocus();
46079 editor.fontSelect.dom,
46085 if(!this.disable.formats){
46086 this.formatCombo = new Roo.form.ComboBox({
46087 store: new Roo.data.SimpleStore({
46090 data : this.formats // from states.js
46094 //autoCreate : {tag: "div", size: "20"},
46095 displayField:'tag',
46099 triggerAction: 'all',
46100 emptyText:'Add tag',
46101 selectOnFocus:true,
46104 'select': function(c, r, i) {
46105 editorcore.insertTag(r.get('tag'));
46111 tb.addField(this.formatCombo);
46115 if(!this.disable.format){
46120 btn('strikethrough')
46123 if(!this.disable.fontSize){
46128 btn('increasefontsize', false, editorcore.adjustFont),
46129 btn('decreasefontsize', false, editorcore.adjustFont)
46134 if(!this.disable.colors){
46137 id:editorcore.frameId +'-forecolor',
46138 cls:'x-btn-icon x-edit-forecolor',
46139 clickEvent:'mousedown',
46140 tooltip: this.buttonTips['forecolor'] || undefined,
46142 menu : new Roo.menu.ColorMenu({
46143 allowReselect: true,
46144 focus: Roo.emptyFn,
46147 selectHandler: function(cp, color){
46148 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46149 editor.deferFocus();
46152 clickEvent:'mousedown'
46155 id:editorcore.frameId +'backcolor',
46156 cls:'x-btn-icon x-edit-backcolor',
46157 clickEvent:'mousedown',
46158 tooltip: this.buttonTips['backcolor'] || undefined,
46160 menu : new Roo.menu.ColorMenu({
46161 focus: Roo.emptyFn,
46164 allowReselect: true,
46165 selectHandler: function(cp, color){
46167 editorcore.execCmd('useCSS', false);
46168 editorcore.execCmd('hilitecolor', color);
46169 editorcore.execCmd('useCSS', true);
46170 editor.deferFocus();
46172 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46173 Roo.isSafari || Roo.isIE ? '#'+color : color);
46174 editor.deferFocus();
46178 clickEvent:'mousedown'
46183 // now add all the items...
46186 if(!this.disable.alignments){
46189 btn('justifyleft'),
46190 btn('justifycenter'),
46191 btn('justifyright')
46195 //if(!Roo.isSafari){
46196 if(!this.disable.links){
46199 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46203 if(!this.disable.lists){
46206 btn('insertorderedlist'),
46207 btn('insertunorderedlist')
46210 if(!this.disable.sourceEdit){
46213 btn('sourceedit', true, function(btn){
46214 this.toggleSourceEdit(btn.pressed);
46221 // special menu.. - needs to be tidied up..
46222 if (!this.disable.special) {
46225 cls: 'x-edit-none',
46231 for (var i =0; i < this.specialChars.length; i++) {
46232 smenu.menu.items.push({
46234 html: this.specialChars[i],
46235 handler: function(a,b) {
46236 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46237 //editor.insertAtCursor(a.html);
46251 if (!this.disable.cleanStyles) {
46253 cls: 'x-btn-icon x-btn-clear',
46259 for (var i =0; i < this.cleanStyles.length; i++) {
46260 cmenu.menu.items.push({
46261 actiontype : this.cleanStyles[i],
46262 html: 'Remove ' + this.cleanStyles[i],
46263 handler: function(a,b) {
46266 var c = Roo.get(editorcore.doc.body);
46267 c.select('[style]').each(function(s) {
46268 s.dom.style.removeProperty(a.actiontype);
46270 editorcore.syncValue();
46275 cmenu.menu.items.push({
46276 actiontype : 'tablewidths',
46277 html: 'Remove Table Widths',
46278 handler: function(a,b) {
46279 editorcore.cleanTableWidths();
46280 editorcore.syncValue();
46284 cmenu.menu.items.push({
46285 actiontype : 'word',
46286 html: 'Remove MS Word Formating',
46287 handler: function(a,b) {
46288 editorcore.cleanWord();
46289 editorcore.syncValue();
46294 cmenu.menu.items.push({
46295 actiontype : 'all',
46296 html: 'Remove All Styles',
46297 handler: function(a,b) {
46299 var c = Roo.get(editorcore.doc.body);
46300 c.select('[style]').each(function(s) {
46301 s.dom.removeAttribute('style');
46303 editorcore.syncValue();
46308 cmenu.menu.items.push({
46309 actiontype : 'all',
46310 html: 'Remove All CSS Classes',
46311 handler: function(a,b) {
46313 var c = Roo.get(editorcore.doc.body);
46314 c.select('[class]').each(function(s) {
46315 s.dom.removeAttribute('class');
46317 editorcore.cleanWord();
46318 editorcore.syncValue();
46323 cmenu.menu.items.push({
46324 actiontype : 'tidy',
46325 html: 'Tidy HTML Source',
46326 handler: function(a,b) {
46327 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46328 editorcore.syncValue();
46337 if (!this.disable.specialElements) {
46340 cls: 'x-edit-none',
46345 for (var i =0; i < this.specialElements.length; i++) {
46346 semenu.menu.items.push(
46348 handler: function(a,b) {
46349 editor.insertAtCursor(this.ihtml);
46351 }, this.specialElements[i])
46363 for(var i =0; i< this.btns.length;i++) {
46364 var b = Roo.factory(this.btns[i],Roo.form);
46365 b.cls = 'x-edit-none';
46367 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46368 b.cls += ' x-init-enable';
46371 b.scope = editorcore;
46379 // disable everything...
46381 this.tb.items.each(function(item){
46384 item.id != editorcore.frameId+ '-sourceedit' &&
46385 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46391 this.rendered = true;
46393 // the all the btns;
46394 editor.on('editorevent', this.updateToolbar, this);
46395 // other toolbars need to implement this..
46396 //editor.on('editmodechange', this.updateToolbar, this);
46400 relayBtnCmd : function(btn) {
46401 this.editorcore.relayCmd(btn.cmd);
46403 // private used internally
46404 createLink : function(){
46405 Roo.log("create link?");
46406 var url = prompt(this.createLinkText, this.defaultLinkValue);
46407 if(url && url != 'http:/'+'/'){
46408 this.editorcore.relayCmd('createlink', url);
46414 * Protected method that will not generally be called directly. It triggers
46415 * a toolbar update by reading the markup state of the current selection in the editor.
46417 updateToolbar: function(){
46419 if(!this.editorcore.activated){
46420 this.editor.onFirstFocus();
46424 var btns = this.tb.items.map,
46425 doc = this.editorcore.doc,
46426 frameId = this.editorcore.frameId;
46428 if(!this.disable.font && !Roo.isSafari){
46430 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46431 if(name != this.fontSelect.dom.value){
46432 this.fontSelect.dom.value = name;
46436 if(!this.disable.format){
46437 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46438 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46439 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46440 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46442 if(!this.disable.alignments){
46443 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46444 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46445 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46447 if(!Roo.isSafari && !this.disable.lists){
46448 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46449 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46452 var ans = this.editorcore.getAllAncestors();
46453 if (this.formatCombo) {
46456 var store = this.formatCombo.store;
46457 this.formatCombo.setValue("");
46458 for (var i =0; i < ans.length;i++) {
46459 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46461 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46469 // hides menus... - so this cant be on a menu...
46470 Roo.menu.MenuMgr.hideAll();
46472 //this.editorsyncValue();
46476 createFontOptions : function(){
46477 var buf = [], fs = this.fontFamilies, ff, lc;
46481 for(var i = 0, len = fs.length; i< len; i++){
46483 lc = ff.toLowerCase();
46485 '<option value="',lc,'" style="font-family:',ff,';"',
46486 (this.defaultFont == lc ? ' selected="true">' : '>'),
46491 return buf.join('');
46494 toggleSourceEdit : function(sourceEditMode){
46496 Roo.log("toolbar toogle");
46497 if(sourceEditMode === undefined){
46498 sourceEditMode = !this.sourceEditMode;
46500 this.sourceEditMode = sourceEditMode === true;
46501 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46502 // just toggle the button?
46503 if(btn.pressed !== this.sourceEditMode){
46504 btn.toggle(this.sourceEditMode);
46508 if(sourceEditMode){
46509 Roo.log("disabling buttons");
46510 this.tb.items.each(function(item){
46511 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46517 Roo.log("enabling buttons");
46518 if(this.editorcore.initialized){
46519 this.tb.items.each(function(item){
46525 Roo.log("calling toggole on editor");
46526 // tell the editor that it's been pressed..
46527 this.editor.toggleSourceEdit(sourceEditMode);
46531 * Object collection of toolbar tooltips for the buttons in the editor. The key
46532 * is the command id associated with that button and the value is a valid QuickTips object.
46537 title: 'Bold (Ctrl+B)',
46538 text: 'Make the selected text bold.',
46539 cls: 'x-html-editor-tip'
46542 title: 'Italic (Ctrl+I)',
46543 text: 'Make the selected text italic.',
46544 cls: 'x-html-editor-tip'
46552 title: 'Bold (Ctrl+B)',
46553 text: 'Make the selected text bold.',
46554 cls: 'x-html-editor-tip'
46557 title: 'Italic (Ctrl+I)',
46558 text: 'Make the selected text italic.',
46559 cls: 'x-html-editor-tip'
46562 title: 'Underline (Ctrl+U)',
46563 text: 'Underline the selected text.',
46564 cls: 'x-html-editor-tip'
46567 title: 'Strikethrough',
46568 text: 'Strikethrough the selected text.',
46569 cls: 'x-html-editor-tip'
46571 increasefontsize : {
46572 title: 'Grow Text',
46573 text: 'Increase the font size.',
46574 cls: 'x-html-editor-tip'
46576 decreasefontsize : {
46577 title: 'Shrink Text',
46578 text: 'Decrease the font size.',
46579 cls: 'x-html-editor-tip'
46582 title: 'Text Highlight Color',
46583 text: 'Change the background color of the selected text.',
46584 cls: 'x-html-editor-tip'
46587 title: 'Font Color',
46588 text: 'Change the color of the selected text.',
46589 cls: 'x-html-editor-tip'
46592 title: 'Align Text Left',
46593 text: 'Align text to the left.',
46594 cls: 'x-html-editor-tip'
46597 title: 'Center Text',
46598 text: 'Center text in the editor.',
46599 cls: 'x-html-editor-tip'
46602 title: 'Align Text Right',
46603 text: 'Align text to the right.',
46604 cls: 'x-html-editor-tip'
46606 insertunorderedlist : {
46607 title: 'Bullet List',
46608 text: 'Start a bulleted list.',
46609 cls: 'x-html-editor-tip'
46611 insertorderedlist : {
46612 title: 'Numbered List',
46613 text: 'Start a numbered list.',
46614 cls: 'x-html-editor-tip'
46617 title: 'Hyperlink',
46618 text: 'Make the selected text a hyperlink.',
46619 cls: 'x-html-editor-tip'
46622 title: 'Source Edit',
46623 text: 'Switch to source editing mode.',
46624 cls: 'x-html-editor-tip'
46628 onDestroy : function(){
46631 this.tb.items.each(function(item){
46633 item.menu.removeAll();
46635 item.menu.el.destroy();
46643 onFirstFocus: function() {
46644 this.tb.items.each(function(item){
46653 // <script type="text/javascript">
46656 * Ext JS Library 1.1.1
46657 * Copyright(c) 2006-2007, Ext JS, LLC.
46664 * @class Roo.form.HtmlEditor.ToolbarContext
46669 new Roo.form.HtmlEditor({
46672 { xtype: 'ToolbarStandard', styles : {} }
46673 { xtype: 'ToolbarContext', disable : {} }
46679 * @config : {Object} disable List of elements to disable.. (not done yet.)
46680 * @config : {Object} styles Map of styles available.
46684 Roo.form.HtmlEditor.ToolbarContext = function(config)
46687 Roo.apply(this, config);
46688 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46689 // dont call parent... till later.
46690 this.styles = this.styles || {};
46695 Roo.form.HtmlEditor.ToolbarContext.types = {
46707 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46773 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46778 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46788 style : 'fontFamily',
46789 displayField: 'display',
46790 optname : 'font-family',
46839 // should we really allow this??
46840 // should this just be
46851 style : 'fontFamily',
46852 displayField: 'display',
46853 optname : 'font-family',
46860 style : 'fontFamily',
46861 displayField: 'display',
46862 optname : 'font-family',
46869 style : 'fontFamily',
46870 displayField: 'display',
46871 optname : 'font-family',
46882 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46883 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46885 Roo.form.HtmlEditor.ToolbarContext.options = {
46887 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46888 [ 'Courier New', 'Courier New'],
46889 [ 'Tahoma', 'Tahoma'],
46890 [ 'Times New Roman,serif', 'Times'],
46891 [ 'Verdana','Verdana' ]
46895 // fixme - these need to be configurable..
46898 //Roo.form.HtmlEditor.ToolbarContext.types
46901 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46908 editorcore : false,
46910 * @cfg {Object} disable List of toolbar elements to disable
46915 * @cfg {Object} styles List of styles
46916 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46918 * These must be defined in the page, so they get rendered correctly..
46929 init : function(editor)
46931 this.editor = editor;
46932 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46933 var editorcore = this.editorcore;
46935 var fid = editorcore.frameId;
46937 function btn(id, toggle, handler){
46938 var xid = fid + '-'+ id ;
46942 cls : 'x-btn-icon x-edit-'+id,
46943 enableToggle:toggle !== false,
46944 scope: editorcore, // was editor...
46945 handler:handler||editorcore.relayBtnCmd,
46946 clickEvent:'mousedown',
46947 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46951 // create a new element.
46952 var wdiv = editor.wrap.createChild({
46954 }, editor.wrap.dom.firstChild.nextSibling, true);
46956 // can we do this more than once??
46958 // stop form submits
46961 // disable everything...
46962 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46963 this.toolbars = {};
46965 for (var i in ty) {
46967 this.toolbars[i] = this.buildToolbar(ty[i],i);
46969 this.tb = this.toolbars.BODY;
46971 this.buildFooter();
46972 this.footer.show();
46973 editor.on('hide', function( ) { this.footer.hide() }, this);
46974 editor.on('show', function( ) { this.footer.show() }, this);
46977 this.rendered = true;
46979 // the all the btns;
46980 editor.on('editorevent', this.updateToolbar, this);
46981 // other toolbars need to implement this..
46982 //editor.on('editmodechange', this.updateToolbar, this);
46988 * Protected method that will not generally be called directly. It triggers
46989 * a toolbar update by reading the markup state of the current selection in the editor.
46991 * Note you can force an update by calling on('editorevent', scope, false)
46993 updateToolbar: function(editor,ev,sel){
46996 // capture mouse up - this is handy for selecting images..
46997 // perhaps should go somewhere else...
46998 if(!this.editorcore.activated){
46999 this.editor.onFirstFocus();
47005 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
47006 // selectNode - might want to handle IE?
47008 (ev.type == 'mouseup' || ev.type == 'click' ) &&
47009 ev.target && ev.target.tagName == 'IMG') {
47010 // they have click on an image...
47011 // let's see if we can change the selection...
47014 var nodeRange = sel.ownerDocument.createRange();
47016 nodeRange.selectNode(sel);
47018 nodeRange.selectNodeContents(sel);
47020 //nodeRange.collapse(true);
47021 var s = this.editorcore.win.getSelection();
47022 s.removeAllRanges();
47023 s.addRange(nodeRange);
47027 var updateFooter = sel ? false : true;
47030 var ans = this.editorcore.getAllAncestors();
47033 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47036 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47037 sel = sel ? sel : this.editorcore.doc.body;
47038 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47041 // pick a menu that exists..
47042 var tn = sel.tagName.toUpperCase();
47043 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47045 tn = sel.tagName.toUpperCase();
47047 var lastSel = this.tb.selectedNode;
47049 this.tb.selectedNode = sel;
47051 // if current menu does not match..
47053 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47056 ///console.log("show: " + tn);
47057 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47060 this.tb.items.first().el.innerHTML = tn + ': ';
47063 // update attributes
47064 if (this.tb.fields) {
47065 this.tb.fields.each(function(e) {
47067 e.setValue(sel.style[e.stylename]);
47070 e.setValue(sel.getAttribute(e.attrname));
47074 var hasStyles = false;
47075 for(var i in this.styles) {
47082 var st = this.tb.fields.item(0);
47084 st.store.removeAll();
47087 var cn = sel.className.split(/\s+/);
47090 if (this.styles['*']) {
47092 Roo.each(this.styles['*'], function(v) {
47093 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47096 if (this.styles[tn]) {
47097 Roo.each(this.styles[tn], function(v) {
47098 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47102 st.store.loadData(avs);
47106 // flag our selected Node.
47107 this.tb.selectedNode = sel;
47110 Roo.menu.MenuMgr.hideAll();
47114 if (!updateFooter) {
47115 //this.footDisp.dom.innerHTML = '';
47118 // update the footer
47122 this.footerEls = ans.reverse();
47123 Roo.each(this.footerEls, function(a,i) {
47124 if (!a) { return; }
47125 html += html.length ? ' > ' : '';
47127 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47132 var sz = this.footDisp.up('td').getSize();
47133 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47134 this.footDisp.dom.style.marginLeft = '5px';
47136 this.footDisp.dom.style.overflow = 'hidden';
47138 this.footDisp.dom.innerHTML = html;
47140 //this.editorsyncValue();
47147 onDestroy : function(){
47150 this.tb.items.each(function(item){
47152 item.menu.removeAll();
47154 item.menu.el.destroy();
47162 onFirstFocus: function() {
47163 // need to do this for all the toolbars..
47164 this.tb.items.each(function(item){
47168 buildToolbar: function(tlist, nm)
47170 var editor = this.editor;
47171 var editorcore = this.editorcore;
47172 // create a new element.
47173 var wdiv = editor.wrap.createChild({
47175 }, editor.wrap.dom.firstChild.nextSibling, true);
47178 var tb = new Roo.Toolbar(wdiv);
47181 tb.add(nm+ ": ");
47184 for(var i in this.styles) {
47189 if (styles && styles.length) {
47191 // this needs a multi-select checkbox...
47192 tb.addField( new Roo.form.ComboBox({
47193 store: new Roo.data.SimpleStore({
47195 fields: ['val', 'selected'],
47198 name : '-roo-edit-className',
47199 attrname : 'className',
47200 displayField: 'val',
47204 triggerAction: 'all',
47205 emptyText:'Select Style',
47206 selectOnFocus:true,
47209 'select': function(c, r, i) {
47210 // initial support only for on class per el..
47211 tb.selectedNode.className = r ? r.get('val') : '';
47212 editorcore.syncValue();
47219 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47220 var tbops = tbc.options;
47222 for (var i in tlist) {
47224 var item = tlist[i];
47225 tb.add(item.title + ": ");
47228 //optname == used so you can configure the options available..
47229 var opts = item.opts ? item.opts : false;
47230 if (item.optname) {
47231 opts = tbops[item.optname];
47236 // opts == pulldown..
47237 tb.addField( new Roo.form.ComboBox({
47238 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47240 fields: ['val', 'display'],
47243 name : '-roo-edit-' + i,
47245 stylename : item.style ? item.style : false,
47246 displayField: item.displayField ? item.displayField : 'val',
47247 valueField : 'val',
47249 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47251 triggerAction: 'all',
47252 emptyText:'Select',
47253 selectOnFocus:true,
47254 width: item.width ? item.width : 130,
47256 'select': function(c, r, i) {
47258 tb.selectedNode.style[c.stylename] = r.get('val');
47261 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47270 tb.addField( new Roo.form.TextField({
47273 //allowBlank:false,
47278 tb.addField( new Roo.form.TextField({
47279 name: '-roo-edit-' + i,
47286 'change' : function(f, nv, ov) {
47287 tb.selectedNode.setAttribute(f.attrname, nv);
47288 editorcore.syncValue();
47301 text: 'Stylesheets',
47304 click : function ()
47306 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47314 text: 'Remove Tag',
47317 click : function ()
47320 // undo does not work.
47322 var sn = tb.selectedNode;
47324 var pn = sn.parentNode;
47326 var stn = sn.childNodes[0];
47327 var en = sn.childNodes[sn.childNodes.length - 1 ];
47328 while (sn.childNodes.length) {
47329 var node = sn.childNodes[0];
47330 sn.removeChild(node);
47332 pn.insertBefore(node, sn);
47335 pn.removeChild(sn);
47336 var range = editorcore.createRange();
47338 range.setStart(stn,0);
47339 range.setEnd(en,0); //????
47340 //range.selectNode(sel);
47343 var selection = editorcore.getSelection();
47344 selection.removeAllRanges();
47345 selection.addRange(range);
47349 //_this.updateToolbar(null, null, pn);
47350 _this.updateToolbar(null, null, null);
47351 _this.footDisp.dom.innerHTML = '';
47361 tb.el.on('click', function(e){
47362 e.preventDefault(); // what does this do?
47364 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47367 // dont need to disable them... as they will get hidden
47372 buildFooter : function()
47375 var fel = this.editor.wrap.createChild();
47376 this.footer = new Roo.Toolbar(fel);
47377 // toolbar has scrolly on left / right?
47378 var footDisp= new Roo.Toolbar.Fill();
47384 handler : function() {
47385 _t.footDisp.scrollTo('left',0,true)
47389 this.footer.add( footDisp );
47394 handler : function() {
47396 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47400 var fel = Roo.get(footDisp.el);
47401 fel.addClass('x-editor-context');
47402 this.footDispWrap = fel;
47403 this.footDispWrap.overflow = 'hidden';
47405 this.footDisp = fel.createChild();
47406 this.footDispWrap.on('click', this.onContextClick, this)
47410 onContextClick : function (ev,dom)
47412 ev.preventDefault();
47413 var cn = dom.className;
47415 if (!cn.match(/x-ed-loc-/)) {
47418 var n = cn.split('-').pop();
47419 var ans = this.footerEls;
47423 var range = this.editorcore.createRange();
47425 range.selectNodeContents(sel);
47426 //range.selectNode(sel);
47429 var selection = this.editorcore.getSelection();
47430 selection.removeAllRanges();
47431 selection.addRange(range);
47435 this.updateToolbar(null, null, sel);
47452 * Ext JS Library 1.1.1
47453 * Copyright(c) 2006-2007, Ext JS, LLC.
47455 * Originally Released Under LGPL - original licence link has changed is not relivant.
47458 * <script type="text/javascript">
47462 * @class Roo.form.BasicForm
47463 * @extends Roo.util.Observable
47464 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47466 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47467 * @param {Object} config Configuration options
47469 Roo.form.BasicForm = function(el, config){
47470 this.allItems = [];
47471 this.childForms = [];
47472 Roo.apply(this, config);
47474 * The Roo.form.Field items in this form.
47475 * @type MixedCollection
47479 this.items = new Roo.util.MixedCollection(false, function(o){
47480 return o.id || (o.id = Roo.id());
47484 * @event beforeaction
47485 * Fires before any action is performed. Return false to cancel the action.
47486 * @param {Form} this
47487 * @param {Action} action The action to be performed
47489 beforeaction: true,
47491 * @event actionfailed
47492 * Fires when an action fails.
47493 * @param {Form} this
47494 * @param {Action} action The action that failed
47496 actionfailed : true,
47498 * @event actioncomplete
47499 * Fires when an action is completed.
47500 * @param {Form} this
47501 * @param {Action} action The action that completed
47503 actioncomplete : true
47508 Roo.form.BasicForm.superclass.constructor.call(this);
47510 Roo.form.BasicForm.popover.apply();
47513 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47515 * @cfg {String} method
47516 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47519 * @cfg {DataReader} reader
47520 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47521 * This is optional as there is built-in support for processing JSON.
47524 * @cfg {DataReader} errorReader
47525 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47526 * This is completely optional as there is built-in support for processing JSON.
47529 * @cfg {String} url
47530 * The URL to use for form actions if one isn't supplied in the action options.
47533 * @cfg {Boolean} fileUpload
47534 * Set to true if this form is a file upload.
47538 * @cfg {Object} baseParams
47539 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47544 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47549 activeAction : null,
47552 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47553 * or setValues() data instead of when the form was first created.
47555 trackResetOnLoad : false,
47559 * childForms - used for multi-tab forms
47562 childForms : false,
47565 * allItems - full list of fields.
47571 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47572 * element by passing it or its id or mask the form itself by passing in true.
47575 waitMsgTarget : false,
47580 disableMask : false,
47583 * @cfg {Boolean} errorMask (true|false) default false
47588 * @cfg {Number} maskOffset Default 100
47593 initEl : function(el){
47594 this.el = Roo.get(el);
47595 this.id = this.el.id || Roo.id();
47596 this.el.on('submit', this.onSubmit, this);
47597 this.el.addClass('x-form');
47601 onSubmit : function(e){
47606 * Returns true if client-side validation on the form is successful.
47609 isValid : function(){
47611 var target = false;
47612 this.items.each(function(f){
47619 if(!target && f.el.isVisible(true)){
47624 if(this.errorMask && !valid){
47625 Roo.form.BasicForm.popover.mask(this, target);
47631 * Returns array of invalid form fields.
47635 invalidFields : function()
47638 this.items.each(function(f){
47651 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47654 isDirty : function(){
47656 this.items.each(function(f){
47666 * Returns true if any fields in this form have changed since their original load. (New version)
47670 hasChanged : function()
47673 this.items.each(function(f){
47674 if(f.hasChanged()){
47683 * Resets all hasChanged to 'false' -
47684 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47685 * So hasChanged storage is only to be used for this purpose
47688 resetHasChanged : function()
47690 this.items.each(function(f){
47691 f.resetHasChanged();
47698 * Performs a predefined action (submit or load) or custom actions you define on this form.
47699 * @param {String} actionName The name of the action type
47700 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47701 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47702 * accept other config options):
47704 Property Type Description
47705 ---------------- --------------- ----------------------------------------------------------------------------------
47706 url String The url for the action (defaults to the form's url)
47707 method String The form method to use (defaults to the form's method, or POST if not defined)
47708 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47709 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47710 validate the form on the client (defaults to false)
47712 * @return {BasicForm} this
47714 doAction : function(action, options){
47715 if(typeof action == 'string'){
47716 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47718 if(this.fireEvent('beforeaction', this, action) !== false){
47719 this.beforeAction(action);
47720 action.run.defer(100, action);
47726 * Shortcut to do a submit action.
47727 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47728 * @return {BasicForm} this
47730 submit : function(options){
47731 this.doAction('submit', options);
47736 * Shortcut to do a load action.
47737 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47738 * @return {BasicForm} this
47740 load : function(options){
47741 this.doAction('load', options);
47746 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47747 * @param {Record} record The record to edit
47748 * @return {BasicForm} this
47750 updateRecord : function(record){
47751 record.beginEdit();
47752 var fs = record.fields;
47753 fs.each(function(f){
47754 var field = this.findField(f.name);
47756 record.set(f.name, field.getValue());
47764 * Loads an Roo.data.Record into this form.
47765 * @param {Record} record The record to load
47766 * @return {BasicForm} this
47768 loadRecord : function(record){
47769 this.setValues(record.data);
47774 beforeAction : function(action){
47775 var o = action.options;
47777 if(!this.disableMask) {
47778 if(this.waitMsgTarget === true){
47779 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47780 }else if(this.waitMsgTarget){
47781 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47782 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47784 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47792 afterAction : function(action, success){
47793 this.activeAction = null;
47794 var o = action.options;
47796 if(!this.disableMask) {
47797 if(this.waitMsgTarget === true){
47799 }else if(this.waitMsgTarget){
47800 this.waitMsgTarget.unmask();
47802 Roo.MessageBox.updateProgress(1);
47803 Roo.MessageBox.hide();
47811 Roo.callback(o.success, o.scope, [this, action]);
47812 this.fireEvent('actioncomplete', this, action);
47816 // failure condition..
47817 // we have a scenario where updates need confirming.
47818 // eg. if a locking scenario exists..
47819 // we look for { errors : { needs_confirm : true }} in the response.
47821 (typeof(action.result) != 'undefined') &&
47822 (typeof(action.result.errors) != 'undefined') &&
47823 (typeof(action.result.errors.needs_confirm) != 'undefined')
47826 Roo.MessageBox.confirm(
47827 "Change requires confirmation",
47828 action.result.errorMsg,
47833 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47843 Roo.callback(o.failure, o.scope, [this, action]);
47844 // show an error message if no failed handler is set..
47845 if (!this.hasListener('actionfailed')) {
47846 Roo.MessageBox.alert("Error",
47847 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47848 action.result.errorMsg :
47849 "Saving Failed, please check your entries or try again"
47853 this.fireEvent('actionfailed', this, action);
47859 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47860 * @param {String} id The value to search for
47863 findField : function(id){
47864 var field = this.items.get(id);
47866 this.items.each(function(f){
47867 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47873 return field || null;
47877 * Add a secondary form to this one,
47878 * Used to provide tabbed forms. One form is primary, with hidden values
47879 * which mirror the elements from the other forms.
47881 * @param {Roo.form.Form} form to add.
47884 addForm : function(form)
47887 if (this.childForms.indexOf(form) > -1) {
47891 this.childForms.push(form);
47893 Roo.each(form.allItems, function (fe) {
47895 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
47896 if (this.findField(n)) { // already added..
47899 var add = new Roo.form.Hidden({
47902 add.render(this.el);
47909 * Mark fields in this form invalid in bulk.
47910 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
47911 * @return {BasicForm} this
47913 markInvalid : function(errors){
47914 if(errors instanceof Array){
47915 for(var i = 0, len = errors.length; i < len; i++){
47916 var fieldError = errors[i];
47917 var f = this.findField(fieldError.id);
47919 f.markInvalid(fieldError.msg);
47925 if(typeof errors[id] != 'function' && (field = this.findField(id))){
47926 field.markInvalid(errors[id]);
47930 Roo.each(this.childForms || [], function (f) {
47931 f.markInvalid(errors);
47938 * Set values for fields in this form in bulk.
47939 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
47940 * @return {BasicForm} this
47942 setValues : function(values){
47943 if(values instanceof Array){ // array of objects
47944 for(var i = 0, len = values.length; i < len; i++){
47946 var f = this.findField(v.id);
47948 f.setValue(v.value);
47949 if(this.trackResetOnLoad){
47950 f.originalValue = f.getValue();
47954 }else{ // object hash
47957 if(typeof values[id] != 'function' && (field = this.findField(id))){
47959 if (field.setFromData &&
47960 field.valueField &&
47961 field.displayField &&
47962 // combos' with local stores can
47963 // be queried via setValue()
47964 // to set their value..
47965 (field.store && !field.store.isLocal)
47969 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47970 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47971 field.setFromData(sd);
47974 field.setValue(values[id]);
47978 if(this.trackResetOnLoad){
47979 field.originalValue = field.getValue();
47984 this.resetHasChanged();
47987 Roo.each(this.childForms || [], function (f) {
47988 f.setValues(values);
47989 f.resetHasChanged();
47996 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47997 * they are returned as an array.
47998 * @param {Boolean} asString
48001 getValues : function(asString){
48002 if (this.childForms) {
48003 // copy values from the child forms
48004 Roo.each(this.childForms, function (f) {
48005 this.setValues(f.getValues());
48010 if (typeof(FormData) != 'undefined' && asString !== true) {
48011 // this relies on a 'recent' version of chrome apparently...
48013 var fd = (new FormData(this.el.dom)).entries();
48015 var ent = fd.next();
48016 while (!ent.done) {
48017 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
48028 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
48029 if(asString === true){
48032 return Roo.urlDecode(fs);
48036 * Returns the fields in this form as an object with key/value pairs.
48037 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48040 getFieldValues : function(with_hidden)
48042 if (this.childForms) {
48043 // copy values from the child forms
48044 // should this call getFieldValues - probably not as we do not currently copy
48045 // hidden fields when we generate..
48046 Roo.each(this.childForms, function (f) {
48047 this.setValues(f.getValues());
48052 this.items.each(function(f){
48053 if (!f.getName()) {
48056 var v = f.getValue();
48057 if (f.inputType =='radio') {
48058 if (typeof(ret[f.getName()]) == 'undefined') {
48059 ret[f.getName()] = ''; // empty..
48062 if (!f.el.dom.checked) {
48066 v = f.el.dom.value;
48070 // not sure if this supported any more..
48071 if ((typeof(v) == 'object') && f.getRawValue) {
48072 v = f.getRawValue() ; // dates..
48074 // combo boxes where name != hiddenName...
48075 if (f.name != f.getName()) {
48076 ret[f.name] = f.getRawValue();
48078 ret[f.getName()] = v;
48085 * Clears all invalid messages in this form.
48086 * @return {BasicForm} this
48088 clearInvalid : function(){
48089 this.items.each(function(f){
48093 Roo.each(this.childForms || [], function (f) {
48102 * Resets this form.
48103 * @return {BasicForm} this
48105 reset : function(){
48106 this.items.each(function(f){
48110 Roo.each(this.childForms || [], function (f) {
48113 this.resetHasChanged();
48119 * Add Roo.form components to this form.
48120 * @param {Field} field1
48121 * @param {Field} field2 (optional)
48122 * @param {Field} etc (optional)
48123 * @return {BasicForm} this
48126 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48132 * Removes a field from the items collection (does NOT remove its markup).
48133 * @param {Field} field
48134 * @return {BasicForm} this
48136 remove : function(field){
48137 this.items.remove(field);
48142 * Looks at the fields in this form, checks them for an id attribute,
48143 * and calls applyTo on the existing dom element with that id.
48144 * @return {BasicForm} this
48146 render : function(){
48147 this.items.each(function(f){
48148 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48156 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48157 * @param {Object} values
48158 * @return {BasicForm} this
48160 applyToFields : function(o){
48161 this.items.each(function(f){
48168 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48169 * @param {Object} values
48170 * @return {BasicForm} this
48172 applyIfToFields : function(o){
48173 this.items.each(function(f){
48181 Roo.BasicForm = Roo.form.BasicForm;
48183 Roo.apply(Roo.form.BasicForm, {
48197 intervalID : false,
48203 if(this.isApplied){
48208 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48209 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48210 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48211 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48214 this.maskEl.top.enableDisplayMode("block");
48215 this.maskEl.left.enableDisplayMode("block");
48216 this.maskEl.bottom.enableDisplayMode("block");
48217 this.maskEl.right.enableDisplayMode("block");
48219 Roo.get(document.body).on('click', function(){
48223 Roo.get(document.body).on('touchstart', function(){
48227 this.isApplied = true
48230 mask : function(form, target)
48234 this.target = target;
48236 if(!this.form.errorMask || !target.el){
48240 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48242 var ot = this.target.el.calcOffsetsTo(scrollable);
48244 var scrollTo = ot[1] - this.form.maskOffset;
48246 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48248 scrollable.scrollTo('top', scrollTo);
48250 var el = this.target.wrap || this.target.el;
48252 var box = el.getBox();
48254 this.maskEl.top.setStyle('position', 'absolute');
48255 this.maskEl.top.setStyle('z-index', 10000);
48256 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48257 this.maskEl.top.setLeft(0);
48258 this.maskEl.top.setTop(0);
48259 this.maskEl.top.show();
48261 this.maskEl.left.setStyle('position', 'absolute');
48262 this.maskEl.left.setStyle('z-index', 10000);
48263 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48264 this.maskEl.left.setLeft(0);
48265 this.maskEl.left.setTop(box.y - this.padding);
48266 this.maskEl.left.show();
48268 this.maskEl.bottom.setStyle('position', 'absolute');
48269 this.maskEl.bottom.setStyle('z-index', 10000);
48270 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48271 this.maskEl.bottom.setLeft(0);
48272 this.maskEl.bottom.setTop(box.bottom + this.padding);
48273 this.maskEl.bottom.show();
48275 this.maskEl.right.setStyle('position', 'absolute');
48276 this.maskEl.right.setStyle('z-index', 10000);
48277 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48278 this.maskEl.right.setLeft(box.right + this.padding);
48279 this.maskEl.right.setTop(box.y - this.padding);
48280 this.maskEl.right.show();
48282 this.intervalID = window.setInterval(function() {
48283 Roo.form.BasicForm.popover.unmask();
48286 window.onwheel = function(){ return false;};
48288 (function(){ this.isMasked = true; }).defer(500, this);
48292 unmask : function()
48294 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48298 this.maskEl.top.setStyle('position', 'absolute');
48299 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48300 this.maskEl.top.hide();
48302 this.maskEl.left.setStyle('position', 'absolute');
48303 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48304 this.maskEl.left.hide();
48306 this.maskEl.bottom.setStyle('position', 'absolute');
48307 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48308 this.maskEl.bottom.hide();
48310 this.maskEl.right.setStyle('position', 'absolute');
48311 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48312 this.maskEl.right.hide();
48314 window.onwheel = function(){ return true;};
48316 if(this.intervalID){
48317 window.clearInterval(this.intervalID);
48318 this.intervalID = false;
48321 this.isMasked = false;
48329 * Ext JS Library 1.1.1
48330 * Copyright(c) 2006-2007, Ext JS, LLC.
48332 * Originally Released Under LGPL - original licence link has changed is not relivant.
48335 * <script type="text/javascript">
48339 * @class Roo.form.Form
48340 * @extends Roo.form.BasicForm
48341 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48343 * @param {Object} config Configuration options
48345 Roo.form.Form = function(config){
48347 if (config.items) {
48348 xitems = config.items;
48349 delete config.items;
48353 Roo.form.Form.superclass.constructor.call(this, null, config);
48354 this.url = this.url || this.action;
48356 this.root = new Roo.form.Layout(Roo.applyIf({
48360 this.active = this.root;
48362 * Array of all the buttons that have been added to this form via {@link addButton}
48366 this.allItems = [];
48369 * @event clientvalidation
48370 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48371 * @param {Form} this
48372 * @param {Boolean} valid true if the form has passed client-side validation
48374 clientvalidation: true,
48377 * Fires when the form is rendered
48378 * @param {Roo.form.Form} form
48383 if (this.progressUrl) {
48384 // push a hidden field onto the list of fields..
48388 name : 'UPLOAD_IDENTIFIER'
48393 Roo.each(xitems, this.addxtype, this);
48397 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48399 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48402 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48405 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48407 buttonAlign:'center',
48410 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48415 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48416 * This property cascades to child containers if not set.
48421 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48422 * fires a looping event with that state. This is required to bind buttons to the valid
48423 * state using the config value formBind:true on the button.
48425 monitorValid : false,
48428 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48433 * @cfg {String} progressUrl - Url to return progress data
48436 progressUrl : false,
48438 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48439 * sending a formdata with extra parameters - eg uploaded elements.
48445 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48446 * fields are added and the column is closed. If no fields are passed the column remains open
48447 * until end() is called.
48448 * @param {Object} config The config to pass to the column
48449 * @param {Field} field1 (optional)
48450 * @param {Field} field2 (optional)
48451 * @param {Field} etc (optional)
48452 * @return Column The column container object
48454 column : function(c){
48455 var col = new Roo.form.Column(c);
48457 if(arguments.length > 1){ // duplicate code required because of Opera
48458 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48465 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48466 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48467 * until end() is called.
48468 * @param {Object} config The config to pass to the fieldset
48469 * @param {Field} field1 (optional)
48470 * @param {Field} field2 (optional)
48471 * @param {Field} etc (optional)
48472 * @return FieldSet The fieldset container object
48474 fieldset : function(c){
48475 var fs = new Roo.form.FieldSet(c);
48477 if(arguments.length > 1){ // duplicate code required because of Opera
48478 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48485 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48486 * fields are added and the container is closed. If no fields are passed the container remains open
48487 * until end() is called.
48488 * @param {Object} config The config to pass to the Layout
48489 * @param {Field} field1 (optional)
48490 * @param {Field} field2 (optional)
48491 * @param {Field} etc (optional)
48492 * @return Layout The container object
48494 container : function(c){
48495 var l = new Roo.form.Layout(c);
48497 if(arguments.length > 1){ // duplicate code required because of Opera
48498 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48505 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48506 * @param {Object} container A Roo.form.Layout or subclass of Layout
48507 * @return {Form} this
48509 start : function(c){
48510 // cascade label info
48511 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48512 this.active.stack.push(c);
48513 c.ownerCt = this.active;
48519 * Closes the current open container
48520 * @return {Form} this
48523 if(this.active == this.root){
48526 this.active = this.active.ownerCt;
48531 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48532 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48533 * as the label of the field.
48534 * @param {Field} field1
48535 * @param {Field} field2 (optional)
48536 * @param {Field} etc. (optional)
48537 * @return {Form} this
48540 this.active.stack.push.apply(this.active.stack, arguments);
48541 this.allItems.push.apply(this.allItems,arguments);
48543 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48544 if(a[i].isFormField){
48549 Roo.form.Form.superclass.add.apply(this, r);
48559 * Find any element that has been added to a form, using it's ID or name
48560 * This can include framesets, columns etc. along with regular fields..
48561 * @param {String} id - id or name to find.
48563 * @return {Element} e - or false if nothing found.
48565 findbyId : function(id)
48571 Roo.each(this.allItems, function(f){
48572 if (f.id == id || f.name == id ){
48583 * Render this form into the passed container. This should only be called once!
48584 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48585 * @return {Form} this
48587 render : function(ct)
48593 var o = this.autoCreate || {
48595 method : this.method || 'POST',
48596 id : this.id || Roo.id()
48598 this.initEl(ct.createChild(o));
48600 this.root.render(this.el);
48604 this.items.each(function(f){
48605 f.render('x-form-el-'+f.id);
48608 if(this.buttons.length > 0){
48609 // tables are required to maintain order and for correct IE layout
48610 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48611 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48612 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48614 var tr = tb.getElementsByTagName('tr')[0];
48615 for(var i = 0, len = this.buttons.length; i < len; i++) {
48616 var b = this.buttons[i];
48617 var td = document.createElement('td');
48618 td.className = 'x-form-btn-td';
48619 b.render(tr.appendChild(td));
48622 if(this.monitorValid){ // initialize after render
48623 this.startMonitoring();
48625 this.fireEvent('rendered', this);
48630 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48631 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48632 * object or a valid Roo.DomHelper element config
48633 * @param {Function} handler The function called when the button is clicked
48634 * @param {Object} scope (optional) The scope of the handler function
48635 * @return {Roo.Button}
48637 addButton : function(config, handler, scope){
48641 minWidth: this.minButtonWidth,
48644 if(typeof config == "string"){
48647 Roo.apply(bc, config);
48649 var btn = new Roo.Button(null, bc);
48650 this.buttons.push(btn);
48655 * Adds a series of form elements (using the xtype property as the factory method.
48656 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48657 * @param {Object} config
48660 addxtype : function()
48662 var ar = Array.prototype.slice.call(arguments, 0);
48664 for(var i = 0; i < ar.length; i++) {
48666 continue; // skip -- if this happends something invalid got sent, we
48667 // should ignore it, as basically that interface element will not show up
48668 // and that should be pretty obvious!!
48671 if (Roo.form[ar[i].xtype]) {
48673 var fe = Roo.factory(ar[i], Roo.form);
48679 fe.store.form = this;
48684 this.allItems.push(fe);
48685 if (fe.items && fe.addxtype) {
48686 fe.addxtype.apply(fe, fe.items);
48696 // console.log('adding ' + ar[i].xtype);
48698 if (ar[i].xtype == 'Button') {
48699 //console.log('adding button');
48700 //console.log(ar[i]);
48701 this.addButton(ar[i]);
48702 this.allItems.push(fe);
48706 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48707 alert('end is not supported on xtype any more, use items');
48709 // //console.log('adding end');
48717 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48718 * option "monitorValid"
48720 startMonitoring : function(){
48723 Roo.TaskMgr.start({
48724 run : this.bindHandler,
48725 interval : this.monitorPoll || 200,
48732 * Stops monitoring of the valid state of this form
48734 stopMonitoring : function(){
48735 this.bound = false;
48739 bindHandler : function(){
48741 return false; // stops binding
48744 this.items.each(function(f){
48745 if(!f.isValid(true)){
48750 for(var i = 0, len = this.buttons.length; i < len; i++){
48751 var btn = this.buttons[i];
48752 if(btn.formBind === true && btn.disabled === valid){
48753 btn.setDisabled(!valid);
48756 this.fireEvent('clientvalidation', this, valid);
48770 Roo.Form = Roo.form.Form;
48773 * Ext JS Library 1.1.1
48774 * Copyright(c) 2006-2007, Ext JS, LLC.
48776 * Originally Released Under LGPL - original licence link has changed is not relivant.
48779 * <script type="text/javascript">
48782 // as we use this in bootstrap.
48783 Roo.namespace('Roo.form');
48785 * @class Roo.form.Action
48786 * Internal Class used to handle form actions
48788 * @param {Roo.form.BasicForm} el The form element or its id
48789 * @param {Object} config Configuration options
48794 // define the action interface
48795 Roo.form.Action = function(form, options){
48797 this.options = options || {};
48800 * Client Validation Failed
48803 Roo.form.Action.CLIENT_INVALID = 'client';
48805 * Server Validation Failed
48808 Roo.form.Action.SERVER_INVALID = 'server';
48810 * Connect to Server Failed
48813 Roo.form.Action.CONNECT_FAILURE = 'connect';
48815 * Reading Data from Server Failed
48818 Roo.form.Action.LOAD_FAILURE = 'load';
48820 Roo.form.Action.prototype = {
48822 failureType : undefined,
48823 response : undefined,
48824 result : undefined,
48826 // interface method
48827 run : function(options){
48831 // interface method
48832 success : function(response){
48836 // interface method
48837 handleResponse : function(response){
48841 // default connection failure
48842 failure : function(response){
48844 this.response = response;
48845 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48846 this.form.afterAction(this, false);
48849 processResponse : function(response){
48850 this.response = response;
48851 if(!response.responseText){
48854 this.result = this.handleResponse(response);
48855 return this.result;
48858 // utility functions used internally
48859 getUrl : function(appendParams){
48860 var url = this.options.url || this.form.url || this.form.el.dom.action;
48862 var p = this.getParams();
48864 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
48870 getMethod : function(){
48871 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
48874 getParams : function(){
48875 var bp = this.form.baseParams;
48876 var p = this.options.params;
48878 if(typeof p == "object"){
48879 p = Roo.urlEncode(Roo.applyIf(p, bp));
48880 }else if(typeof p == 'string' && bp){
48881 p += '&' + Roo.urlEncode(bp);
48884 p = Roo.urlEncode(bp);
48889 createCallback : function(){
48891 success: this.success,
48892 failure: this.failure,
48894 timeout: (this.form.timeout*1000),
48895 upload: this.form.fileUpload ? this.success : undefined
48900 Roo.form.Action.Submit = function(form, options){
48901 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
48904 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
48907 haveProgress : false,
48908 uploadComplete : false,
48910 // uploadProgress indicator.
48911 uploadProgress : function()
48913 if (!this.form.progressUrl) {
48917 if (!this.haveProgress) {
48918 Roo.MessageBox.progress("Uploading", "Uploading");
48920 if (this.uploadComplete) {
48921 Roo.MessageBox.hide();
48925 this.haveProgress = true;
48927 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
48929 var c = new Roo.data.Connection();
48931 url : this.form.progressUrl,
48936 success : function(req){
48937 //console.log(data);
48941 rdata = Roo.decode(req.responseText)
48943 Roo.log("Invalid data from server..");
48947 if (!rdata || !rdata.success) {
48949 Roo.MessageBox.alert(Roo.encode(rdata));
48952 var data = rdata.data;
48954 if (this.uploadComplete) {
48955 Roo.MessageBox.hide();
48960 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
48961 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
48964 this.uploadProgress.defer(2000,this);
48967 failure: function(data) {
48968 Roo.log('progress url failed ');
48979 // run get Values on the form, so it syncs any secondary forms.
48980 this.form.getValues();
48982 var o = this.options;
48983 var method = this.getMethod();
48984 var isPost = method == 'POST';
48985 if(o.clientValidation === false || this.form.isValid()){
48987 if (this.form.progressUrl) {
48988 this.form.findField('UPLOAD_IDENTIFIER').setValue(
48989 (new Date() * 1) + '' + Math.random());
48994 Roo.Ajax.request(Roo.apply(this.createCallback(), {
48995 form:this.form.el.dom,
48996 url:this.getUrl(!isPost),
48998 params:isPost ? this.getParams() : null,
48999 isUpload: this.form.fileUpload,
49000 formData : this.form.formData
49003 this.uploadProgress();
49005 }else if (o.clientValidation !== false){ // client validation failed
49006 this.failureType = Roo.form.Action.CLIENT_INVALID;
49007 this.form.afterAction(this, false);
49011 success : function(response)
49013 this.uploadComplete= true;
49014 if (this.haveProgress) {
49015 Roo.MessageBox.hide();
49019 var result = this.processResponse(response);
49020 if(result === true || result.success){
49021 this.form.afterAction(this, true);
49025 this.form.markInvalid(result.errors);
49026 this.failureType = Roo.form.Action.SERVER_INVALID;
49028 this.form.afterAction(this, false);
49030 failure : function(response)
49032 this.uploadComplete= true;
49033 if (this.haveProgress) {
49034 Roo.MessageBox.hide();
49037 this.response = response;
49038 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49039 this.form.afterAction(this, false);
49042 handleResponse : function(response){
49043 if(this.form.errorReader){
49044 var rs = this.form.errorReader.read(response);
49047 for(var i = 0, len = rs.records.length; i < len; i++) {
49048 var r = rs.records[i];
49049 errors[i] = r.data;
49052 if(errors.length < 1){
49056 success : rs.success,
49062 ret = Roo.decode(response.responseText);
49066 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49076 Roo.form.Action.Load = function(form, options){
49077 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49078 this.reader = this.form.reader;
49081 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49086 Roo.Ajax.request(Roo.apply(
49087 this.createCallback(), {
49088 method:this.getMethod(),
49089 url:this.getUrl(false),
49090 params:this.getParams()
49094 success : function(response){
49096 var result = this.processResponse(response);
49097 if(result === true || !result.success || !result.data){
49098 this.failureType = Roo.form.Action.LOAD_FAILURE;
49099 this.form.afterAction(this, false);
49102 this.form.clearInvalid();
49103 this.form.setValues(result.data);
49104 this.form.afterAction(this, true);
49107 handleResponse : function(response){
49108 if(this.form.reader){
49109 var rs = this.form.reader.read(response);
49110 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49112 success : rs.success,
49116 return Roo.decode(response.responseText);
49120 Roo.form.Action.ACTION_TYPES = {
49121 'load' : Roo.form.Action.Load,
49122 'submit' : Roo.form.Action.Submit
49125 * Ext JS Library 1.1.1
49126 * Copyright(c) 2006-2007, Ext JS, LLC.
49128 * Originally Released Under LGPL - original licence link has changed is not relivant.
49131 * <script type="text/javascript">
49135 * @class Roo.form.Layout
49136 * @extends Roo.Component
49137 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49139 * @param {Object} config Configuration options
49141 Roo.form.Layout = function(config){
49143 if (config.items) {
49144 xitems = config.items;
49145 delete config.items;
49147 Roo.form.Layout.superclass.constructor.call(this, config);
49149 Roo.each(xitems, this.addxtype, this);
49153 Roo.extend(Roo.form.Layout, Roo.Component, {
49155 * @cfg {String/Object} autoCreate
49156 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49159 * @cfg {String/Object/Function} style
49160 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49161 * a function which returns such a specification.
49164 * @cfg {String} labelAlign
49165 * Valid values are "left," "top" and "right" (defaults to "left")
49168 * @cfg {Number} labelWidth
49169 * Fixed width in pixels of all field labels (defaults to undefined)
49172 * @cfg {Boolean} clear
49173 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49177 * @cfg {String} labelSeparator
49178 * The separator to use after field labels (defaults to ':')
49180 labelSeparator : ':',
49182 * @cfg {Boolean} hideLabels
49183 * True to suppress the display of field labels in this layout (defaults to false)
49185 hideLabels : false,
49188 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49193 onRender : function(ct, position){
49194 if(this.el){ // from markup
49195 this.el = Roo.get(this.el);
49196 }else { // generate
49197 var cfg = this.getAutoCreate();
49198 this.el = ct.createChild(cfg, position);
49201 this.el.applyStyles(this.style);
49203 if(this.labelAlign){
49204 this.el.addClass('x-form-label-'+this.labelAlign);
49206 if(this.hideLabels){
49207 this.labelStyle = "display:none";
49208 this.elementStyle = "padding-left:0;";
49210 if(typeof this.labelWidth == 'number'){
49211 this.labelStyle = "width:"+this.labelWidth+"px;";
49212 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49214 if(this.labelAlign == 'top'){
49215 this.labelStyle = "width:auto;";
49216 this.elementStyle = "padding-left:0;";
49219 var stack = this.stack;
49220 var slen = stack.length;
49222 if(!this.fieldTpl){
49223 var t = new Roo.Template(
49224 '<div class="x-form-item {5}">',
49225 '<label for="{0}" style="{2}">{1}{4}</label>',
49226 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49228 '</div><div class="x-form-clear-left"></div>'
49230 t.disableFormats = true;
49232 Roo.form.Layout.prototype.fieldTpl = t;
49234 for(var i = 0; i < slen; i++) {
49235 if(stack[i].isFormField){
49236 this.renderField(stack[i]);
49238 this.renderComponent(stack[i]);
49243 this.el.createChild({cls:'x-form-clear'});
49248 renderField : function(f){
49249 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49252 f.labelStyle||this.labelStyle||'', //2
49253 this.elementStyle||'', //3
49254 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49255 f.itemCls||this.itemCls||'' //5
49256 ], true).getPrevSibling());
49260 renderComponent : function(c){
49261 c.render(c.isLayout ? this.el : this.el.createChild());
49264 * Adds a object form elements (using the xtype property as the factory method.)
49265 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49266 * @param {Object} config
49268 addxtype : function(o)
49270 // create the lement.
49271 o.form = this.form;
49272 var fe = Roo.factory(o, Roo.form);
49273 this.form.allItems.push(fe);
49274 this.stack.push(fe);
49276 if (fe.isFormField) {
49277 this.form.items.add(fe);
49285 * @class Roo.form.Column
49286 * @extends Roo.form.Layout
49287 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49289 * @param {Object} config Configuration options
49291 Roo.form.Column = function(config){
49292 Roo.form.Column.superclass.constructor.call(this, config);
49295 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49297 * @cfg {Number/String} width
49298 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49301 * @cfg {String/Object} autoCreate
49302 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49306 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49309 onRender : function(ct, position){
49310 Roo.form.Column.superclass.onRender.call(this, ct, position);
49312 this.el.setWidth(this.width);
49319 * @class Roo.form.Row
49320 * @extends Roo.form.Layout
49321 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49323 * @param {Object} config Configuration options
49327 Roo.form.Row = function(config){
49328 Roo.form.Row.superclass.constructor.call(this, config);
49331 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49333 * @cfg {Number/String} width
49334 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49337 * @cfg {Number/String} height
49338 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49340 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49344 onRender : function(ct, position){
49345 //console.log('row render');
49347 var t = new Roo.Template(
49348 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49349 '<label for="{0}" style="{2}">{1}{4}</label>',
49350 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49354 t.disableFormats = true;
49356 Roo.form.Layout.prototype.rowTpl = t;
49358 this.fieldTpl = this.rowTpl;
49360 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49361 var labelWidth = 100;
49363 if ((this.labelAlign != 'top')) {
49364 if (typeof this.labelWidth == 'number') {
49365 labelWidth = this.labelWidth
49367 this.padWidth = 20 + labelWidth;
49371 Roo.form.Column.superclass.onRender.call(this, ct, position);
49373 this.el.setWidth(this.width);
49376 this.el.setHeight(this.height);
49381 renderField : function(f){
49382 f.fieldEl = this.fieldTpl.append(this.el, [
49383 f.id, f.fieldLabel,
49384 f.labelStyle||this.labelStyle||'',
49385 this.elementStyle||'',
49386 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49387 f.itemCls||this.itemCls||'',
49388 f.width ? f.width + this.padWidth : 160 + this.padWidth
49395 * @class Roo.form.FieldSet
49396 * @extends Roo.form.Layout
49397 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49399 * @param {Object} config Configuration options
49401 Roo.form.FieldSet = function(config){
49402 Roo.form.FieldSet.superclass.constructor.call(this, config);
49405 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49407 * @cfg {String} legend
49408 * The text to display as the legend for the FieldSet (defaults to '')
49411 * @cfg {String/Object} autoCreate
49412 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49416 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49419 onRender : function(ct, position){
49420 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49422 this.setLegend(this.legend);
49427 setLegend : function(text){
49429 this.el.child('legend').update(text);
49434 * Ext JS Library 1.1.1
49435 * Copyright(c) 2006-2007, Ext JS, LLC.
49437 * Originally Released Under LGPL - original licence link has changed is not relivant.
49440 * <script type="text/javascript">
49443 * @class Roo.form.VTypes
49444 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49447 Roo.form.VTypes = function(){
49448 // closure these in so they are only created once.
49449 var alpha = /^[a-zA-Z_]+$/;
49450 var alphanum = /^[a-zA-Z0-9_]+$/;
49451 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49452 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49454 // All these messages and functions are configurable
49457 * The function used to validate email addresses
49458 * @param {String} value The email address
49460 'email' : function(v){
49461 return email.test(v);
49464 * The error text to display when the email validation function returns false
49467 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49469 * The keystroke filter mask to be applied on email input
49472 'emailMask' : /[a-z0-9_\.\-@]/i,
49475 * The function used to validate URLs
49476 * @param {String} value The URL
49478 'url' : function(v){
49479 return url.test(v);
49482 * The error text to display when the url validation function returns false
49485 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49488 * The function used to validate alpha values
49489 * @param {String} value The value
49491 'alpha' : function(v){
49492 return alpha.test(v);
49495 * The error text to display when the alpha validation function returns false
49498 'alphaText' : 'This field should only contain letters and _',
49500 * The keystroke filter mask to be applied on alpha input
49503 'alphaMask' : /[a-z_]/i,
49506 * The function used to validate alphanumeric values
49507 * @param {String} value The value
49509 'alphanum' : function(v){
49510 return alphanum.test(v);
49513 * The error text to display when the alphanumeric validation function returns false
49516 'alphanumText' : 'This field should only contain letters, numbers and _',
49518 * The keystroke filter mask to be applied on alphanumeric input
49521 'alphanumMask' : /[a-z0-9_]/i
49523 }();//<script type="text/javascript">
49526 * @class Roo.form.FCKeditor
49527 * @extends Roo.form.TextArea
49528 * Wrapper around the FCKEditor http://www.fckeditor.net
49530 * Creates a new FCKeditor
49531 * @param {Object} config Configuration options
49533 Roo.form.FCKeditor = function(config){
49534 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49537 * @event editorinit
49538 * Fired when the editor is initialized - you can add extra handlers here..
49539 * @param {FCKeditor} this
49540 * @param {Object} the FCK object.
49547 Roo.form.FCKeditor.editors = { };
49548 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49550 //defaultAutoCreate : {
49551 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49555 * @cfg {Object} fck options - see fck manual for details.
49560 * @cfg {Object} fck toolbar set (Basic or Default)
49562 toolbarSet : 'Basic',
49564 * @cfg {Object} fck BasePath
49566 basePath : '/fckeditor/',
49574 onRender : function(ct, position)
49577 this.defaultAutoCreate = {
49579 style:"width:300px;height:60px;",
49580 autocomplete: "new-password"
49583 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49586 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49587 if(this.preventScrollbars){
49588 this.el.setStyle("overflow", "hidden");
49590 this.el.setHeight(this.growMin);
49593 //console.log('onrender' + this.getId() );
49594 Roo.form.FCKeditor.editors[this.getId()] = this;
49597 this.replaceTextarea() ;
49601 getEditor : function() {
49602 return this.fckEditor;
49605 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49606 * @param {Mixed} value The value to set
49610 setValue : function(value)
49612 //console.log('setValue: ' + value);
49614 if(typeof(value) == 'undefined') { // not sure why this is happending...
49617 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49619 //if(!this.el || !this.getEditor()) {
49620 // this.value = value;
49621 //this.setValue.defer(100,this,[value]);
49625 if(!this.getEditor()) {
49629 this.getEditor().SetData(value);
49636 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49637 * @return {Mixed} value The field value
49639 getValue : function()
49642 if (this.frame && this.frame.dom.style.display == 'none') {
49643 return Roo.form.FCKeditor.superclass.getValue.call(this);
49646 if(!this.el || !this.getEditor()) {
49648 // this.getValue.defer(100,this);
49653 var value=this.getEditor().GetData();
49654 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49655 return Roo.form.FCKeditor.superclass.getValue.call(this);
49661 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49662 * @return {Mixed} value The field value
49664 getRawValue : function()
49666 if (this.frame && this.frame.dom.style.display == 'none') {
49667 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49670 if(!this.el || !this.getEditor()) {
49671 //this.getRawValue.defer(100,this);
49678 var value=this.getEditor().GetData();
49679 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49680 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49684 setSize : function(w,h) {
49688 //if (this.frame && this.frame.dom.style.display == 'none') {
49689 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49692 //if(!this.el || !this.getEditor()) {
49693 // this.setSize.defer(100,this, [w,h]);
49699 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49701 this.frame.dom.setAttribute('width', w);
49702 this.frame.dom.setAttribute('height', h);
49703 this.frame.setSize(w,h);
49707 toggleSourceEdit : function(value) {
49711 this.el.dom.style.display = value ? '' : 'none';
49712 this.frame.dom.style.display = value ? 'none' : '';
49717 focus: function(tag)
49719 if (this.frame.dom.style.display == 'none') {
49720 return Roo.form.FCKeditor.superclass.focus.call(this);
49722 if(!this.el || !this.getEditor()) {
49723 this.focus.defer(100,this, [tag]);
49730 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49731 this.getEditor().Focus();
49733 if (!this.getEditor().Selection.GetSelection()) {
49734 this.focus.defer(100,this, [tag]);
49739 var r = this.getEditor().EditorDocument.createRange();
49740 r.setStart(tgs[0],0);
49741 r.setEnd(tgs[0],0);
49742 this.getEditor().Selection.GetSelection().removeAllRanges();
49743 this.getEditor().Selection.GetSelection().addRange(r);
49744 this.getEditor().Focus();
49751 replaceTextarea : function()
49753 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49756 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49758 // We must check the elements firstly using the Id and then the name.
49759 var oTextarea = document.getElementById( this.getId() );
49761 var colElementsByName = document.getElementsByName( this.getId() ) ;
49763 oTextarea.style.display = 'none' ;
49765 if ( oTextarea.tabIndex ) {
49766 this.TabIndex = oTextarea.tabIndex ;
49769 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49770 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49771 this.frame = Roo.get(this.getId() + '___Frame')
49774 _getConfigHtml : function()
49778 for ( var o in this.fckconfig ) {
49779 sConfig += sConfig.length > 0 ? '&' : '';
49780 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49783 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49787 _getIFrameHtml : function()
49789 var sFile = 'fckeditor.html' ;
49790 /* no idea what this is about..
49793 if ( (/fcksource=true/i).test( window.top.location.search ) )
49794 sFile = 'fckeditor.original.html' ;
49799 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49800 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49803 var html = '<iframe id="' + this.getId() +
49804 '___Frame" src="' + sLink +
49805 '" width="' + this.width +
49806 '" height="' + this.height + '"' +
49807 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
49808 ' frameborder="0" scrolling="no"></iframe>' ;
49813 _insertHtmlBefore : function( html, element )
49815 if ( element.insertAdjacentHTML ) {
49817 element.insertAdjacentHTML( 'beforeBegin', html ) ;
49819 var oRange = document.createRange() ;
49820 oRange.setStartBefore( element ) ;
49821 var oFragment = oRange.createContextualFragment( html );
49822 element.parentNode.insertBefore( oFragment, element ) ;
49835 //Roo.reg('fckeditor', Roo.form.FCKeditor);
49837 function FCKeditor_OnComplete(editorInstance){
49838 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
49839 f.fckEditor = editorInstance;
49840 //console.log("loaded");
49841 f.fireEvent('editorinit', f, editorInstance);
49861 //<script type="text/javascript">
49863 * @class Roo.form.GridField
49864 * @extends Roo.form.Field
49865 * Embed a grid (or editable grid into a form)
49868 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
49870 * xgrid.store = Roo.data.Store
49871 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
49872 * xgrid.store.reader = Roo.data.JsonReader
49876 * Creates a new GridField
49877 * @param {Object} config Configuration options
49879 Roo.form.GridField = function(config){
49880 Roo.form.GridField.superclass.constructor.call(this, config);
49884 Roo.extend(Roo.form.GridField, Roo.form.Field, {
49886 * @cfg {Number} width - used to restrict width of grid..
49890 * @cfg {Number} height - used to restrict height of grid..
49894 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
49900 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49901 * {tag: "input", type: "checkbox", autocomplete: "off"})
49903 // defaultAutoCreate : { tag: 'div' },
49904 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
49906 * @cfg {String} addTitle Text to include for adding a title.
49910 onResize : function(){
49911 Roo.form.Field.superclass.onResize.apply(this, arguments);
49914 initEvents : function(){
49915 // Roo.form.Checkbox.superclass.initEvents.call(this);
49916 // has no events...
49921 getResizeEl : function(){
49925 getPositionEl : function(){
49930 onRender : function(ct, position){
49932 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
49933 var style = this.style;
49936 Roo.form.GridField.superclass.onRender.call(this, ct, position);
49937 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
49938 this.viewEl = this.wrap.createChild({ tag: 'div' });
49940 this.viewEl.applyStyles(style);
49943 this.viewEl.setWidth(this.width);
49946 this.viewEl.setHeight(this.height);
49948 //if(this.inputValue !== undefined){
49949 //this.setValue(this.value);
49952 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
49955 this.grid.render();
49956 this.grid.getDataSource().on('remove', this.refreshValue, this);
49957 this.grid.getDataSource().on('update', this.refreshValue, this);
49958 this.grid.on('afteredit', this.refreshValue, this);
49964 * Sets the value of the item.
49965 * @param {String} either an object or a string..
49967 setValue : function(v){
49969 v = v || []; // empty set..
49970 // this does not seem smart - it really only affects memoryproxy grids..
49971 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
49972 var ds = this.grid.getDataSource();
49973 // assumes a json reader..
49975 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
49976 ds.loadData( data);
49978 // clear selection so it does not get stale.
49979 if (this.grid.sm) {
49980 this.grid.sm.clearSelections();
49983 Roo.form.GridField.superclass.setValue.call(this, v);
49984 this.refreshValue();
49985 // should load data in the grid really....
49989 refreshValue: function() {
49991 this.grid.getDataSource().each(function(r) {
49994 this.el.dom.value = Roo.encode(val);
50002 * Ext JS Library 1.1.1
50003 * Copyright(c) 2006-2007, Ext JS, LLC.
50005 * Originally Released Under LGPL - original licence link has changed is not relivant.
50008 * <script type="text/javascript">
50011 * @class Roo.form.DisplayField
50012 * @extends Roo.form.Field
50013 * A generic Field to display non-editable data.
50014 * @cfg {Boolean} closable (true|false) default false
50016 * Creates a new Display Field item.
50017 * @param {Object} config Configuration options
50019 Roo.form.DisplayField = function(config){
50020 Roo.form.DisplayField.superclass.constructor.call(this, config);
50025 * Fires after the click the close btn
50026 * @param {Roo.form.DisplayField} this
50032 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50033 inputType: 'hidden',
50039 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50041 focusClass : undefined,
50043 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50045 fieldClass: 'x-form-field',
50048 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50050 valueRenderer: undefined,
50054 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50055 * {tag: "input", type: "checkbox", autocomplete: "off"})
50058 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50062 onResize : function(){
50063 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50067 initEvents : function(){
50068 // Roo.form.Checkbox.superclass.initEvents.call(this);
50069 // has no events...
50072 this.closeEl.on('click', this.onClose, this);
50078 getResizeEl : function(){
50082 getPositionEl : function(){
50087 onRender : function(ct, position){
50089 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50090 //if(this.inputValue !== undefined){
50091 this.wrap = this.el.wrap();
50093 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50096 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50099 if (this.bodyStyle) {
50100 this.viewEl.applyStyles(this.bodyStyle);
50102 //this.viewEl.setStyle('padding', '2px');
50104 this.setValue(this.value);
50109 initValue : Roo.emptyFn,
50114 onClick : function(){
50119 * Sets the checked state of the checkbox.
50120 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50122 setValue : function(v){
50124 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50125 // this might be called before we have a dom element..
50126 if (!this.viewEl) {
50129 this.viewEl.dom.innerHTML = html;
50130 Roo.form.DisplayField.superclass.setValue.call(this, v);
50134 onClose : function(e)
50136 e.preventDefault();
50138 this.fireEvent('close', this);
50147 * @class Roo.form.DayPicker
50148 * @extends Roo.form.Field
50149 * A Day picker show [M] [T] [W] ....
50151 * Creates a new Day Picker
50152 * @param {Object} config Configuration options
50154 Roo.form.DayPicker= function(config){
50155 Roo.form.DayPicker.superclass.constructor.call(this, config);
50159 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50161 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50163 focusClass : undefined,
50165 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50167 fieldClass: "x-form-field",
50170 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50171 * {tag: "input", type: "checkbox", autocomplete: "off"})
50173 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50176 actionMode : 'viewEl',
50180 inputType : 'hidden',
50183 inputElement: false, // real input element?
50184 basedOn: false, // ????
50186 isFormField: true, // not sure where this is needed!!!!
50188 onResize : function(){
50189 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50190 if(!this.boxLabel){
50191 this.el.alignTo(this.wrap, 'c-c');
50195 initEvents : function(){
50196 Roo.form.Checkbox.superclass.initEvents.call(this);
50197 this.el.on("click", this.onClick, this);
50198 this.el.on("change", this.onClick, this);
50202 getResizeEl : function(){
50206 getPositionEl : function(){
50212 onRender : function(ct, position){
50213 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50215 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50217 var r1 = '<table><tr>';
50218 var r2 = '<tr class="x-form-daypick-icons">';
50219 for (var i=0; i < 7; i++) {
50220 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50221 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50224 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50225 viewEl.select('img').on('click', this.onClick, this);
50226 this.viewEl = viewEl;
50229 // this will not work on Chrome!!!
50230 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50231 this.el.on('propertychange', this.setFromHidden, this); //ie
50239 initValue : Roo.emptyFn,
50242 * Returns the checked state of the checkbox.
50243 * @return {Boolean} True if checked, else false
50245 getValue : function(){
50246 return this.el.dom.value;
50251 onClick : function(e){
50252 //this.setChecked(!this.checked);
50253 Roo.get(e.target).toggleClass('x-menu-item-checked');
50254 this.refreshValue();
50255 //if(this.el.dom.checked != this.checked){
50256 // this.setValue(this.el.dom.checked);
50261 refreshValue : function()
50264 this.viewEl.select('img',true).each(function(e,i,n) {
50265 val += e.is(".x-menu-item-checked") ? String(n) : '';
50267 this.setValue(val, true);
50271 * Sets the checked state of the checkbox.
50272 * On is always based on a string comparison between inputValue and the param.
50273 * @param {Boolean/String} value - the value to set
50274 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50276 setValue : function(v,suppressEvent){
50277 if (!this.el.dom) {
50280 var old = this.el.dom.value ;
50281 this.el.dom.value = v;
50282 if (suppressEvent) {
50286 // update display..
50287 this.viewEl.select('img',true).each(function(e,i,n) {
50289 var on = e.is(".x-menu-item-checked");
50290 var newv = v.indexOf(String(n)) > -1;
50292 e.toggleClass('x-menu-item-checked');
50298 this.fireEvent('change', this, v, old);
50303 // handle setting of hidden value by some other method!!?!?
50304 setFromHidden: function()
50309 //console.log("SET FROM HIDDEN");
50310 //alert('setFrom hidden');
50311 this.setValue(this.el.dom.value);
50314 onDestroy : function()
50317 Roo.get(this.viewEl).remove();
50320 Roo.form.DayPicker.superclass.onDestroy.call(this);
50324 * RooJS Library 1.1.1
50325 * Copyright(c) 2008-2011 Alan Knowles
50332 * @class Roo.form.ComboCheck
50333 * @extends Roo.form.ComboBox
50334 * A combobox for multiple select items.
50336 * FIXME - could do with a reset button..
50339 * Create a new ComboCheck
50340 * @param {Object} config Configuration options
50342 Roo.form.ComboCheck = function(config){
50343 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50344 // should verify some data...
50346 // hiddenName = required..
50347 // displayField = required
50348 // valudField == required
50349 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50351 Roo.each(req, function(e) {
50352 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50353 throw "Roo.form.ComboCheck : missing value for: " + e;
50360 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50365 selectedClass: 'x-menu-item-checked',
50368 onRender : function(ct, position){
50374 var cls = 'x-combo-list';
50377 this.tpl = new Roo.Template({
50378 html : '<div class="'+cls+'-item x-menu-check-item">' +
50379 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50380 '<span>{' + this.displayField + '}</span>' +
50387 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50388 this.view.singleSelect = false;
50389 this.view.multiSelect = true;
50390 this.view.toggleSelect = true;
50391 this.pageTb.add(new Roo.Toolbar.Fill(), {
50394 handler: function()
50401 onViewOver : function(e, t){
50407 onViewClick : function(doFocus,index){
50411 select: function () {
50412 //Roo.log("SELECT CALLED");
50415 selectByValue : function(xv, scrollIntoView){
50416 var ar = this.getValueArray();
50419 Roo.each(ar, function(v) {
50420 if(v === undefined || v === null){
50423 var r = this.findRecord(this.valueField, v);
50425 sels.push(this.store.indexOf(r))
50429 this.view.select(sels);
50435 onSelect : function(record, index){
50436 // Roo.log("onselect Called");
50437 // this is only called by the clear button now..
50438 this.view.clearSelections();
50439 this.setValue('[]');
50440 if (this.value != this.valueBefore) {
50441 this.fireEvent('change', this, this.value, this.valueBefore);
50442 this.valueBefore = this.value;
50445 getValueArray : function()
50450 //Roo.log(this.value);
50451 if (typeof(this.value) == 'undefined') {
50454 var ar = Roo.decode(this.value);
50455 return ar instanceof Array ? ar : []; //?? valid?
50458 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50463 expand : function ()
50466 Roo.form.ComboCheck.superclass.expand.call(this);
50467 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50468 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50473 collapse : function(){
50474 Roo.form.ComboCheck.superclass.collapse.call(this);
50475 var sl = this.view.getSelectedIndexes();
50476 var st = this.store;
50480 Roo.each(sl, function(i) {
50482 nv.push(r.get(this.valueField));
50484 this.setValue(Roo.encode(nv));
50485 if (this.value != this.valueBefore) {
50487 this.fireEvent('change', this, this.value, this.valueBefore);
50488 this.valueBefore = this.value;
50493 setValue : function(v){
50497 var vals = this.getValueArray();
50499 Roo.each(vals, function(k) {
50500 var r = this.findRecord(this.valueField, k);
50502 tv.push(r.data[this.displayField]);
50503 }else if(this.valueNotFoundText !== undefined){
50504 tv.push( this.valueNotFoundText );
50509 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50510 this.hiddenField.value = v;
50516 * Ext JS Library 1.1.1
50517 * Copyright(c) 2006-2007, Ext JS, LLC.
50519 * Originally Released Under LGPL - original licence link has changed is not relivant.
50522 * <script type="text/javascript">
50526 * @class Roo.form.Signature
50527 * @extends Roo.form.Field
50531 * @param {Object} config Configuration options
50534 Roo.form.Signature = function(config){
50535 Roo.form.Signature.superclass.constructor.call(this, config);
50537 this.addEvents({// not in used??
50540 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50541 * @param {Roo.form.Signature} combo This combo box
50546 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50547 * @param {Roo.form.ComboBox} combo This combo box
50548 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50554 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50556 * @cfg {Object} labels Label to use when rendering a form.
50560 * confirm : "Confirm"
50565 confirm : "Confirm"
50568 * @cfg {Number} width The signature panel width (defaults to 300)
50572 * @cfg {Number} height The signature panel height (defaults to 100)
50576 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50578 allowBlank : false,
50581 // {Object} signPanel The signature SVG panel element (defaults to {})
50583 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50584 isMouseDown : false,
50585 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50586 isConfirmed : false,
50587 // {String} signatureTmp SVG mapping string (defaults to empty string)
50591 defaultAutoCreate : { // modified by initCompnoent..
50597 onRender : function(ct, position){
50599 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50601 this.wrap = this.el.wrap({
50602 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50605 this.createToolbar(this);
50606 this.signPanel = this.wrap.createChild({
50608 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50612 this.svgID = Roo.id();
50613 this.svgEl = this.signPanel.createChild({
50614 xmlns : 'http://www.w3.org/2000/svg',
50616 id : this.svgID + "-svg",
50618 height: this.height,
50619 viewBox: '0 0 '+this.width+' '+this.height,
50623 id: this.svgID + "-svg-r",
50625 height: this.height,
50630 id: this.svgID + "-svg-l",
50632 y1: (this.height*0.8), // start set the line in 80% of height
50633 x2: this.width, // end
50634 y2: (this.height*0.8), // end set the line in 80% of height
50636 'stroke-width': "1",
50637 'stroke-dasharray': "3",
50638 'shape-rendering': "crispEdges",
50639 'pointer-events': "none"
50643 id: this.svgID + "-svg-p",
50645 'stroke-width': "3",
50647 'pointer-events': 'none'
50652 this.svgBox = this.svgEl.dom.getScreenCTM();
50654 createSVG : function(){
50655 var svg = this.signPanel;
50656 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50659 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50660 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50661 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50662 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50663 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50664 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50665 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50668 isTouchEvent : function(e){
50669 return e.type.match(/^touch/);
50671 getCoords : function (e) {
50672 var pt = this.svgEl.dom.createSVGPoint();
50675 if (this.isTouchEvent(e)) {
50676 pt.x = e.targetTouches[0].clientX;
50677 pt.y = e.targetTouches[0].clientY;
50679 var a = this.svgEl.dom.getScreenCTM();
50680 var b = a.inverse();
50681 var mx = pt.matrixTransform(b);
50682 return mx.x + ',' + mx.y;
50684 //mouse event headler
50685 down : function (e) {
50686 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50687 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50689 this.isMouseDown = true;
50691 e.preventDefault();
50693 move : function (e) {
50694 if (this.isMouseDown) {
50695 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50696 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50699 e.preventDefault();
50701 up : function (e) {
50702 this.isMouseDown = false;
50703 var sp = this.signatureTmp.split(' ');
50706 if(!sp[sp.length-2].match(/^L/)){
50710 this.signatureTmp = sp.join(" ");
50713 if(this.getValue() != this.signatureTmp){
50714 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50715 this.isConfirmed = false;
50717 e.preventDefault();
50721 * Protected method that will not generally be called directly. It
50722 * is called when the editor creates its toolbar. Override this method if you need to
50723 * add custom toolbar buttons.
50724 * @param {HtmlEditor} editor
50726 createToolbar : function(editor){
50727 function btn(id, toggle, handler){
50728 var xid = fid + '-'+ id ;
50732 cls : 'x-btn-icon x-edit-'+id,
50733 enableToggle:toggle !== false,
50734 scope: editor, // was editor...
50735 handler:handler||editor.relayBtnCmd,
50736 clickEvent:'mousedown',
50737 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50743 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50747 cls : ' x-signature-btn x-signature-'+id,
50748 scope: editor, // was editor...
50749 handler: this.reset,
50750 clickEvent:'mousedown',
50751 text: this.labels.clear
50758 cls : ' x-signature-btn x-signature-'+id,
50759 scope: editor, // was editor...
50760 handler: this.confirmHandler,
50761 clickEvent:'mousedown',
50762 text: this.labels.confirm
50769 * when user is clicked confirm then show this image.....
50771 * @return {String} Image Data URI
50773 getImageDataURI : function(){
50774 var svg = this.svgEl.dom.parentNode.innerHTML;
50775 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50780 * @return {Boolean} this.isConfirmed
50782 getConfirmed : function(){
50783 return this.isConfirmed;
50787 * @return {Number} this.width
50789 getWidth : function(){
50794 * @return {Number} this.height
50796 getHeight : function(){
50797 return this.height;
50800 getSignature : function(){
50801 return this.signatureTmp;
50804 reset : function(){
50805 this.signatureTmp = '';
50806 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50807 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
50808 this.isConfirmed = false;
50809 Roo.form.Signature.superclass.reset.call(this);
50811 setSignature : function(s){
50812 this.signatureTmp = s;
50813 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50814 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
50816 this.isConfirmed = false;
50817 Roo.form.Signature.superclass.reset.call(this);
50820 // Roo.log(this.signPanel.dom.contentWindow.up())
50823 setConfirmed : function(){
50827 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
50830 confirmHandler : function(){
50831 if(!this.getSignature()){
50835 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
50836 this.setValue(this.getSignature());
50837 this.isConfirmed = true;
50839 this.fireEvent('confirm', this);
50842 // Subclasses should provide the validation implementation by overriding this
50843 validateValue : function(value){
50844 if(this.allowBlank){
50848 if(this.isConfirmed){
50855 * Ext JS Library 1.1.1
50856 * Copyright(c) 2006-2007, Ext JS, LLC.
50858 * Originally Released Under LGPL - original licence link has changed is not relivant.
50861 * <script type="text/javascript">
50866 * @class Roo.form.ComboBox
50867 * @extends Roo.form.TriggerField
50868 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
50870 * Create a new ComboBox.
50871 * @param {Object} config Configuration options
50873 Roo.form.Select = function(config){
50874 Roo.form.Select.superclass.constructor.call(this, config);
50878 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
50880 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
50883 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
50884 * rendering into an Roo.Editor, defaults to false)
50887 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
50888 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
50891 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
50894 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
50895 * the dropdown list (defaults to undefined, with no header element)
50899 * @cfg {String/Roo.Template} tpl The template to use to render the output
50903 defaultAutoCreate : {tag: "select" },
50905 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
50907 listWidth: undefined,
50909 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
50910 * mode = 'remote' or 'text' if mode = 'local')
50912 displayField: undefined,
50914 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
50915 * mode = 'remote' or 'value' if mode = 'local').
50916 * Note: use of a valueField requires the user make a selection
50917 * in order for a value to be mapped.
50919 valueField: undefined,
50923 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
50924 * field's data value (defaults to the underlying DOM element's name)
50926 hiddenName: undefined,
50928 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
50932 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
50934 selectedClass: 'x-combo-selected',
50936 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
50937 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
50938 * which displays a downward arrow icon).
50940 triggerClass : 'x-form-arrow-trigger',
50942 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
50946 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
50947 * anchor positions (defaults to 'tl-bl')
50949 listAlign: 'tl-bl?',
50951 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
50955 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
50956 * query specified by the allQuery config option (defaults to 'query')
50958 triggerAction: 'query',
50960 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
50961 * (defaults to 4, does not apply if editable = false)
50965 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
50966 * delay (typeAheadDelay) if it matches a known value (defaults to false)
50970 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
50971 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
50975 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
50976 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
50980 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
50981 * when editable = true (defaults to false)
50983 selectOnFocus:false,
50985 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
50987 queryParam: 'query',
50989 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
50990 * when mode = 'remote' (defaults to 'Loading...')
50992 loadingText: 'Loading...',
50994 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
50998 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
51002 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
51003 * traditional select (defaults to true)
51007 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
51011 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
51015 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
51016 * listWidth has a higher value)
51020 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
51021 * allow the user to set arbitrary text into the field (defaults to false)
51023 forceSelection:false,
51025 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
51026 * if typeAhead = true (defaults to 250)
51028 typeAheadDelay : 250,
51030 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
51031 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51033 valueNotFoundText : undefined,
51036 * @cfg {String} defaultValue The value displayed after loading the store.
51041 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51043 blockFocus : false,
51046 * @cfg {Boolean} disableClear Disable showing of clear button.
51048 disableClear : false,
51050 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51052 alwaysQuery : false,
51058 // element that contains real text value.. (when hidden is used..)
51061 onRender : function(ct, position){
51062 Roo.form.Field.prototype.onRender.call(this, ct, position);
51065 this.store.on('beforeload', this.onBeforeLoad, this);
51066 this.store.on('load', this.onLoad, this);
51067 this.store.on('loadexception', this.onLoadException, this);
51068 this.store.load({});
51076 initEvents : function(){
51077 //Roo.form.ComboBox.superclass.initEvents.call(this);
51081 onDestroy : function(){
51084 this.store.un('beforeload', this.onBeforeLoad, this);
51085 this.store.un('load', this.onLoad, this);
51086 this.store.un('loadexception', this.onLoadException, this);
51088 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51092 fireKey : function(e){
51093 if(e.isNavKeyPress() && !this.list.isVisible()){
51094 this.fireEvent("specialkey", this, e);
51099 onResize: function(w, h){
51107 * Allow or prevent the user from directly editing the field text. If false is passed,
51108 * the user will only be able to select from the items defined in the dropdown list. This method
51109 * is the runtime equivalent of setting the 'editable' config option at config time.
51110 * @param {Boolean} value True to allow the user to directly edit the field text
51112 setEditable : function(value){
51117 onBeforeLoad : function(){
51119 Roo.log("Select before load");
51122 this.innerList.update(this.loadingText ?
51123 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51124 //this.restrictHeight();
51125 this.selectedIndex = -1;
51129 onLoad : function(){
51132 var dom = this.el.dom;
51133 dom.innerHTML = '';
51134 var od = dom.ownerDocument;
51136 if (this.emptyText) {
51137 var op = od.createElement('option');
51138 op.setAttribute('value', '');
51139 op.innerHTML = String.format('{0}', this.emptyText);
51140 dom.appendChild(op);
51142 if(this.store.getCount() > 0){
51144 var vf = this.valueField;
51145 var df = this.displayField;
51146 this.store.data.each(function(r) {
51147 // which colmsn to use... testing - cdoe / title..
51148 var op = od.createElement('option');
51149 op.setAttribute('value', r.data[vf]);
51150 op.innerHTML = String.format('{0}', r.data[df]);
51151 dom.appendChild(op);
51153 if (typeof(this.defaultValue != 'undefined')) {
51154 this.setValue(this.defaultValue);
51159 //this.onEmptyResults();
51164 onLoadException : function()
51166 dom.innerHTML = '';
51168 Roo.log("Select on load exception");
51172 Roo.log(this.store.reader.jsonData);
51173 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51174 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51180 onTypeAhead : function(){
51185 onSelect : function(record, index){
51186 Roo.log('on select?');
51188 if(this.fireEvent('beforeselect', this, record, index) !== false){
51189 this.setFromData(index > -1 ? record.data : false);
51191 this.fireEvent('select', this, record, index);
51196 * Returns the currently selected field value or empty string if no value is set.
51197 * @return {String} value The selected value
51199 getValue : function(){
51200 var dom = this.el.dom;
51201 this.value = dom.options[dom.selectedIndex].value;
51207 * Clears any text/value currently set in the field
51209 clearValue : function(){
51211 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51216 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51217 * will be displayed in the field. If the value does not match the data value of an existing item,
51218 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51219 * Otherwise the field will be blank (although the value will still be set).
51220 * @param {String} value The value to match
51222 setValue : function(v){
51223 var d = this.el.dom;
51224 for (var i =0; i < d.options.length;i++) {
51225 if (v == d.options[i].value) {
51226 d.selectedIndex = i;
51234 * @property {Object} the last set data for the element
51239 * Sets the value of the field based on a object which is related to the record format for the store.
51240 * @param {Object} value the value to set as. or false on reset?
51242 setFromData : function(o){
51243 Roo.log('setfrom data?');
51249 reset : function(){
51253 findRecord : function(prop, value){
51258 if(this.store.getCount() > 0){
51259 this.store.each(function(r){
51260 if(r.data[prop] == value){
51270 getName: function()
51272 // returns hidden if it's set..
51273 if (!this.rendered) {return ''};
51274 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51282 onEmptyResults : function(){
51283 Roo.log('empty results');
51288 * Returns true if the dropdown list is expanded, else false.
51290 isExpanded : function(){
51295 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51296 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51297 * @param {String} value The data value of the item to select
51298 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51299 * selected item if it is not currently in view (defaults to true)
51300 * @return {Boolean} True if the value matched an item in the list, else false
51302 selectByValue : function(v, scrollIntoView){
51303 Roo.log('select By Value');
51306 if(v !== undefined && v !== null){
51307 var r = this.findRecord(this.valueField || this.displayField, v);
51309 this.select(this.store.indexOf(r), scrollIntoView);
51317 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51318 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51319 * @param {Number} index The zero-based index of the list item to select
51320 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51321 * selected item if it is not currently in view (defaults to true)
51323 select : function(index, scrollIntoView){
51324 Roo.log('select ');
51327 this.selectedIndex = index;
51328 this.view.select(index);
51329 if(scrollIntoView !== false){
51330 var el = this.view.getNode(index);
51332 this.innerList.scrollChildIntoView(el, false);
51340 validateBlur : function(){
51347 initQuery : function(){
51348 this.doQuery(this.getRawValue());
51352 doForce : function(){
51353 if(this.el.dom.value.length > 0){
51354 this.el.dom.value =
51355 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51361 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51362 * query allowing the query action to be canceled if needed.
51363 * @param {String} query The SQL query to execute
51364 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51365 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51366 * saved in the current store (defaults to false)
51368 doQuery : function(q, forceAll){
51370 Roo.log('doQuery?');
51371 if(q === undefined || q === null){
51376 forceAll: forceAll,
51380 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51384 forceAll = qe.forceAll;
51385 if(forceAll === true || (q.length >= this.minChars)){
51386 if(this.lastQuery != q || this.alwaysQuery){
51387 this.lastQuery = q;
51388 if(this.mode == 'local'){
51389 this.selectedIndex = -1;
51391 this.store.clearFilter();
51393 this.store.filter(this.displayField, q);
51397 this.store.baseParams[this.queryParam] = q;
51399 params: this.getParams(q)
51404 this.selectedIndex = -1;
51411 getParams : function(q){
51413 //p[this.queryParam] = q;
51416 p.limit = this.pageSize;
51422 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51424 collapse : function(){
51429 collapseIf : function(e){
51434 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51436 expand : function(){
51444 * @cfg {Boolean} grow
51448 * @cfg {Number} growMin
51452 * @cfg {Number} growMax
51460 setWidth : function()
51464 getResizeEl : function(){
51467 });//<script type="text/javasscript">
51471 * @class Roo.DDView
51472 * A DnD enabled version of Roo.View.
51473 * @param {Element/String} container The Element in which to create the View.
51474 * @param {String} tpl The template string used to create the markup for each element of the View
51475 * @param {Object} config The configuration properties. These include all the config options of
51476 * {@link Roo.View} plus some specific to this class.<br>
51478 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51479 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51481 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51482 .x-view-drag-insert-above {
51483 border-top:1px dotted #3366cc;
51485 .x-view-drag-insert-below {
51486 border-bottom:1px dotted #3366cc;
51492 Roo.DDView = function(container, tpl, config) {
51493 Roo.DDView.superclass.constructor.apply(this, arguments);
51494 this.getEl().setStyle("outline", "0px none");
51495 this.getEl().unselectable();
51496 if (this.dragGroup) {
51497 this.setDraggable(this.dragGroup.split(","));
51499 if (this.dropGroup) {
51500 this.setDroppable(this.dropGroup.split(","));
51502 if (this.deletable) {
51503 this.setDeletable();
51505 this.isDirtyFlag = false;
51511 Roo.extend(Roo.DDView, Roo.View, {
51512 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51513 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51514 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51515 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51519 reset: Roo.emptyFn,
51521 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51523 validate: function() {
51527 destroy: function() {
51528 this.purgeListeners();
51529 this.getEl.removeAllListeners();
51530 this.getEl().remove();
51531 if (this.dragZone) {
51532 if (this.dragZone.destroy) {
51533 this.dragZone.destroy();
51536 if (this.dropZone) {
51537 if (this.dropZone.destroy) {
51538 this.dropZone.destroy();
51543 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51544 getName: function() {
51548 /** Loads the View from a JSON string representing the Records to put into the Store. */
51549 setValue: function(v) {
51551 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51554 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51555 this.store.proxy = new Roo.data.MemoryProxy(data);
51559 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51560 getValue: function() {
51562 this.store.each(function(rec) {
51563 result += rec.id + ',';
51565 return result.substr(0, result.length - 1) + ')';
51568 getIds: function() {
51569 var i = 0, result = new Array(this.store.getCount());
51570 this.store.each(function(rec) {
51571 result[i++] = rec.id;
51576 isDirty: function() {
51577 return this.isDirtyFlag;
51581 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51582 * whole Element becomes the target, and this causes the drop gesture to append.
51584 getTargetFromEvent : function(e) {
51585 var target = e.getTarget();
51586 while ((target !== null) && (target.parentNode != this.el.dom)) {
51587 target = target.parentNode;
51590 target = this.el.dom.lastChild || this.el.dom;
51596 * Create the drag data which consists of an object which has the property "ddel" as
51597 * the drag proxy element.
51599 getDragData : function(e) {
51600 var target = this.findItemFromChild(e.getTarget());
51602 this.handleSelection(e);
51603 var selNodes = this.getSelectedNodes();
51606 copy: this.copy || (this.allowCopy && e.ctrlKey),
51610 var selectedIndices = this.getSelectedIndexes();
51611 for (var i = 0; i < selectedIndices.length; i++) {
51612 dragData.records.push(this.store.getAt(selectedIndices[i]));
51614 if (selNodes.length == 1) {
51615 dragData.ddel = target.cloneNode(true); // the div element
51617 var div = document.createElement('div'); // create the multi element drag "ghost"
51618 div.className = 'multi-proxy';
51619 for (var i = 0, len = selNodes.length; i < len; i++) {
51620 div.appendChild(selNodes[i].cloneNode(true));
51622 dragData.ddel = div;
51624 //console.log(dragData)
51625 //console.log(dragData.ddel.innerHTML)
51628 //console.log('nodragData')
51632 /** Specify to which ddGroup items in this DDView may be dragged. */
51633 setDraggable: function(ddGroup) {
51634 if (ddGroup instanceof Array) {
51635 Roo.each(ddGroup, this.setDraggable, this);
51638 if (this.dragZone) {
51639 this.dragZone.addToGroup(ddGroup);
51641 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51642 containerScroll: true,
51646 // Draggability implies selection. DragZone's mousedown selects the element.
51647 if (!this.multiSelect) { this.singleSelect = true; }
51649 // Wire the DragZone's handlers up to methods in *this*
51650 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51654 /** Specify from which ddGroup this DDView accepts drops. */
51655 setDroppable: function(ddGroup) {
51656 if (ddGroup instanceof Array) {
51657 Roo.each(ddGroup, this.setDroppable, this);
51660 if (this.dropZone) {
51661 this.dropZone.addToGroup(ddGroup);
51663 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51664 containerScroll: true,
51668 // Wire the DropZone's handlers up to methods in *this*
51669 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51670 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51671 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51672 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51673 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51677 /** Decide whether to drop above or below a View node. */
51678 getDropPoint : function(e, n, dd){
51679 if (n == this.el.dom) { return "above"; }
51680 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51681 var c = t + (b - t) / 2;
51682 var y = Roo.lib.Event.getPageY(e);
51690 onNodeEnter : function(n, dd, e, data){
51694 onNodeOver : function(n, dd, e, data){
51695 var pt = this.getDropPoint(e, n, dd);
51696 // set the insert point style on the target node
51697 var dragElClass = this.dropNotAllowed;
51700 if (pt == "above"){
51701 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51702 targetElClass = "x-view-drag-insert-above";
51704 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51705 targetElClass = "x-view-drag-insert-below";
51707 if (this.lastInsertClass != targetElClass){
51708 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51709 this.lastInsertClass = targetElClass;
51712 return dragElClass;
51715 onNodeOut : function(n, dd, e, data){
51716 this.removeDropIndicators(n);
51719 onNodeDrop : function(n, dd, e, data){
51720 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51723 var pt = this.getDropPoint(e, n, dd);
51724 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51725 if (pt == "below") { insertAt++; }
51726 for (var i = 0; i < data.records.length; i++) {
51727 var r = data.records[i];
51728 var dup = this.store.getById(r.id);
51729 if (dup && (dd != this.dragZone)) {
51730 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51733 this.store.insert(insertAt++, r.copy());
51735 data.source.isDirtyFlag = true;
51737 this.store.insert(insertAt++, r);
51739 this.isDirtyFlag = true;
51742 this.dragZone.cachedTarget = null;
51746 removeDropIndicators : function(n){
51748 Roo.fly(n).removeClass([
51749 "x-view-drag-insert-above",
51750 "x-view-drag-insert-below"]);
51751 this.lastInsertClass = "_noclass";
51756 * Utility method. Add a delete option to the DDView's context menu.
51757 * @param {String} imageUrl The URL of the "delete" icon image.
51759 setDeletable: function(imageUrl) {
51760 if (!this.singleSelect && !this.multiSelect) {
51761 this.singleSelect = true;
51763 var c = this.getContextMenu();
51764 this.contextMenu.on("itemclick", function(item) {
51767 this.remove(this.getSelectedIndexes());
51771 this.contextMenu.add({
51778 /** Return the context menu for this DDView. */
51779 getContextMenu: function() {
51780 if (!this.contextMenu) {
51781 // Create the View's context menu
51782 this.contextMenu = new Roo.menu.Menu({
51783 id: this.id + "-contextmenu"
51785 this.el.on("contextmenu", this.showContextMenu, this);
51787 return this.contextMenu;
51790 disableContextMenu: function() {
51791 if (this.contextMenu) {
51792 this.el.un("contextmenu", this.showContextMenu, this);
51796 showContextMenu: function(e, item) {
51797 item = this.findItemFromChild(e.getTarget());
51800 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51801 this.contextMenu.showAt(e.getXY());
51806 * Remove {@link Roo.data.Record}s at the specified indices.
51807 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
51809 remove: function(selectedIndices) {
51810 selectedIndices = [].concat(selectedIndices);
51811 for (var i = 0; i < selectedIndices.length; i++) {
51812 var rec = this.store.getAt(selectedIndices[i]);
51813 this.store.remove(rec);
51818 * Double click fires the event, but also, if this is draggable, and there is only one other
51819 * related DropZone, it transfers the selected node.
51821 onDblClick : function(e){
51822 var item = this.findItemFromChild(e.getTarget());
51824 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
51827 if (this.dragGroup) {
51828 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
51829 while (targets.indexOf(this.dropZone) > -1) {
51830 targets.remove(this.dropZone);
51832 if (targets.length == 1) {
51833 this.dragZone.cachedTarget = null;
51834 var el = Roo.get(targets[0].getEl());
51835 var box = el.getBox(true);
51836 targets[0].onNodeDrop(el.dom, {
51838 xy: [box.x, box.y + box.height - 1]
51839 }, null, this.getDragData(e));
51845 handleSelection: function(e) {
51846 this.dragZone.cachedTarget = null;
51847 var item = this.findItemFromChild(e.getTarget());
51849 this.clearSelections(true);
51852 if (item && (this.multiSelect || this.singleSelect)){
51853 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
51854 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
51855 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
51856 this.unselect(item);
51858 this.select(item, this.multiSelect && e.ctrlKey);
51859 this.lastSelection = item;
51864 onItemClick : function(item, index, e){
51865 if(this.fireEvent("beforeclick", this, index, item, e) === false){
51871 unselect : function(nodeInfo, suppressEvent){
51872 var node = this.getNode(nodeInfo);
51873 if(node && this.isSelected(node)){
51874 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
51875 Roo.fly(node).removeClass(this.selectedClass);
51876 this.selections.remove(node);
51877 if(!suppressEvent){
51878 this.fireEvent("selectionchange", this, this.selections);
51886 * Ext JS Library 1.1.1
51887 * Copyright(c) 2006-2007, Ext JS, LLC.
51889 * Originally Released Under LGPL - original licence link has changed is not relivant.
51892 * <script type="text/javascript">
51896 * @class Roo.LayoutManager
51897 * @extends Roo.util.Observable
51898 * Base class for layout managers.
51900 Roo.LayoutManager = function(container, config){
51901 Roo.LayoutManager.superclass.constructor.call(this);
51902 this.el = Roo.get(container);
51903 // ie scrollbar fix
51904 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
51905 document.body.scroll = "no";
51906 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
51907 this.el.position('relative');
51909 this.id = this.el.id;
51910 this.el.addClass("x-layout-container");
51911 /** false to disable window resize monitoring @type Boolean */
51912 this.monitorWindowResize = true;
51917 * Fires when a layout is performed.
51918 * @param {Roo.LayoutManager} this
51922 * @event regionresized
51923 * Fires when the user resizes a region.
51924 * @param {Roo.LayoutRegion} region The resized region
51925 * @param {Number} newSize The new size (width for east/west, height for north/south)
51927 "regionresized" : true,
51929 * @event regioncollapsed
51930 * Fires when a region is collapsed.
51931 * @param {Roo.LayoutRegion} region The collapsed region
51933 "regioncollapsed" : true,
51935 * @event regionexpanded
51936 * Fires when a region is expanded.
51937 * @param {Roo.LayoutRegion} region The expanded region
51939 "regionexpanded" : true
51941 this.updating = false;
51942 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
51945 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
51947 * Returns true if this layout is currently being updated
51948 * @return {Boolean}
51950 isUpdating : function(){
51951 return this.updating;
51955 * Suspend the LayoutManager from doing auto-layouts while
51956 * making multiple add or remove calls
51958 beginUpdate : function(){
51959 this.updating = true;
51963 * Restore auto-layouts and optionally disable the manager from performing a layout
51964 * @param {Boolean} noLayout true to disable a layout update
51966 endUpdate : function(noLayout){
51967 this.updating = false;
51973 layout: function(){
51977 onRegionResized : function(region, newSize){
51978 this.fireEvent("regionresized", region, newSize);
51982 onRegionCollapsed : function(region){
51983 this.fireEvent("regioncollapsed", region);
51986 onRegionExpanded : function(region){
51987 this.fireEvent("regionexpanded", region);
51991 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
51992 * performs box-model adjustments.
51993 * @return {Object} The size as an object {width: (the width), height: (the height)}
51995 getViewSize : function(){
51997 if(this.el.dom != document.body){
51998 size = this.el.getSize();
52000 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
52002 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
52003 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
52008 * Returns the Element this layout is bound to.
52009 * @return {Roo.Element}
52011 getEl : function(){
52016 * Returns the specified region.
52017 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
52018 * @return {Roo.LayoutRegion}
52020 getRegion : function(target){
52021 return this.regions[target.toLowerCase()];
52024 onWindowResize : function(){
52025 if(this.monitorWindowResize){
52031 * Ext JS Library 1.1.1
52032 * Copyright(c) 2006-2007, Ext JS, LLC.
52034 * Originally Released Under LGPL - original licence link has changed is not relivant.
52037 * <script type="text/javascript">
52040 * @class Roo.BorderLayout
52041 * @extends Roo.LayoutManager
52042 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52043 * please see: <br><br>
52044 * <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>
52045 * <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>
52048 var layout = new Roo.BorderLayout(document.body, {
52082 preferredTabWidth: 150
52087 var CP = Roo.ContentPanel;
52089 layout.beginUpdate();
52090 layout.add("north", new CP("north", "North"));
52091 layout.add("south", new CP("south", {title: "South", closable: true}));
52092 layout.add("west", new CP("west", {title: "West"}));
52093 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52094 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52095 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52096 layout.getRegion("center").showPanel("center1");
52097 layout.endUpdate();
52100 <b>The container the layout is rendered into can be either the body element or any other element.
52101 If it is not the body element, the container needs to either be an absolute positioned element,
52102 or you will need to add "position:relative" to the css of the container. You will also need to specify
52103 the container size if it is not the body element.</b>
52106 * Create a new BorderLayout
52107 * @param {String/HTMLElement/Element} container The container this layout is bound to
52108 * @param {Object} config Configuration options
52110 Roo.BorderLayout = function(container, config){
52111 config = config || {};
52112 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52113 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52114 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52115 var target = this.factory.validRegions[i];
52116 if(config[target]){
52117 this.addRegion(target, config[target]);
52122 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52124 * Creates and adds a new region if it doesn't already exist.
52125 * @param {String} target The target region key (north, south, east, west or center).
52126 * @param {Object} config The regions config object
52127 * @return {BorderLayoutRegion} The new region
52129 addRegion : function(target, config){
52130 if(!this.regions[target]){
52131 var r = this.factory.create(target, this, config);
52132 this.bindRegion(target, r);
52134 return this.regions[target];
52138 bindRegion : function(name, r){
52139 this.regions[name] = r;
52140 r.on("visibilitychange", this.layout, this);
52141 r.on("paneladded", this.layout, this);
52142 r.on("panelremoved", this.layout, this);
52143 r.on("invalidated", this.layout, this);
52144 r.on("resized", this.onRegionResized, this);
52145 r.on("collapsed", this.onRegionCollapsed, this);
52146 r.on("expanded", this.onRegionExpanded, this);
52150 * Performs a layout update.
52152 layout : function(){
52153 if(this.updating) {
52156 var size = this.getViewSize();
52157 var w = size.width;
52158 var h = size.height;
52163 //var x = 0, y = 0;
52165 var rs = this.regions;
52166 var north = rs["north"];
52167 var south = rs["south"];
52168 var west = rs["west"];
52169 var east = rs["east"];
52170 var center = rs["center"];
52171 //if(this.hideOnLayout){ // not supported anymore
52172 //c.el.setStyle("display", "none");
52174 if(north && north.isVisible()){
52175 var b = north.getBox();
52176 var m = north.getMargins();
52177 b.width = w - (m.left+m.right);
52180 centerY = b.height + b.y + m.bottom;
52181 centerH -= centerY;
52182 north.updateBox(this.safeBox(b));
52184 if(south && south.isVisible()){
52185 var b = south.getBox();
52186 var m = south.getMargins();
52187 b.width = w - (m.left+m.right);
52189 var totalHeight = (b.height + m.top + m.bottom);
52190 b.y = h - totalHeight + m.top;
52191 centerH -= totalHeight;
52192 south.updateBox(this.safeBox(b));
52194 if(west && west.isVisible()){
52195 var b = west.getBox();
52196 var m = west.getMargins();
52197 b.height = centerH - (m.top+m.bottom);
52199 b.y = centerY + m.top;
52200 var totalWidth = (b.width + m.left + m.right);
52201 centerX += totalWidth;
52202 centerW -= totalWidth;
52203 west.updateBox(this.safeBox(b));
52205 if(east && east.isVisible()){
52206 var b = east.getBox();
52207 var m = east.getMargins();
52208 b.height = centerH - (m.top+m.bottom);
52209 var totalWidth = (b.width + m.left + m.right);
52210 b.x = w - totalWidth + m.left;
52211 b.y = centerY + m.top;
52212 centerW -= totalWidth;
52213 east.updateBox(this.safeBox(b));
52216 var m = center.getMargins();
52218 x: centerX + m.left,
52219 y: centerY + m.top,
52220 width: centerW - (m.left+m.right),
52221 height: centerH - (m.top+m.bottom)
52223 //if(this.hideOnLayout){
52224 //center.el.setStyle("display", "block");
52226 center.updateBox(this.safeBox(centerBox));
52229 this.fireEvent("layout", this);
52233 safeBox : function(box){
52234 box.width = Math.max(0, box.width);
52235 box.height = Math.max(0, box.height);
52240 * Adds a ContentPanel (or subclass) to this layout.
52241 * @param {String} target The target region key (north, south, east, west or center).
52242 * @param {Roo.ContentPanel} panel The panel to add
52243 * @return {Roo.ContentPanel} The added panel
52245 add : function(target, panel){
52247 target = target.toLowerCase();
52248 return this.regions[target].add(panel);
52252 * Remove a ContentPanel (or subclass) to this layout.
52253 * @param {String} target The target region key (north, south, east, west or center).
52254 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52255 * @return {Roo.ContentPanel} The removed panel
52257 remove : function(target, panel){
52258 target = target.toLowerCase();
52259 return this.regions[target].remove(panel);
52263 * Searches all regions for a panel with the specified id
52264 * @param {String} panelId
52265 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52267 findPanel : function(panelId){
52268 var rs = this.regions;
52269 for(var target in rs){
52270 if(typeof rs[target] != "function"){
52271 var p = rs[target].getPanel(panelId);
52281 * Searches all regions for a panel with the specified id and activates (shows) it.
52282 * @param {String/ContentPanel} panelId The panels id or the panel itself
52283 * @return {Roo.ContentPanel} The shown panel or null
52285 showPanel : function(panelId) {
52286 var rs = this.regions;
52287 for(var target in rs){
52288 var r = rs[target];
52289 if(typeof r != "function"){
52290 if(r.hasPanel(panelId)){
52291 return r.showPanel(panelId);
52299 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52300 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52302 restoreState : function(provider){
52304 provider = Roo.state.Manager;
52306 var sm = new Roo.LayoutStateManager();
52307 sm.init(this, provider);
52311 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52312 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52313 * a valid ContentPanel config object. Example:
52315 // Create the main layout
52316 var layout = new Roo.BorderLayout('main-ct', {
52327 // Create and add multiple ContentPanels at once via configs
52330 id: 'source-files',
52332 title:'Ext Source Files',
52345 * @param {Object} regions An object containing ContentPanel configs by region name
52347 batchAdd : function(regions){
52348 this.beginUpdate();
52349 for(var rname in regions){
52350 var lr = this.regions[rname];
52352 this.addTypedPanels(lr, regions[rname]);
52359 addTypedPanels : function(lr, ps){
52360 if(typeof ps == 'string'){
52361 lr.add(new Roo.ContentPanel(ps));
52363 else if(ps instanceof Array){
52364 for(var i =0, len = ps.length; i < len; i++){
52365 this.addTypedPanels(lr, ps[i]);
52368 else if(!ps.events){ // raw config?
52370 delete ps.el; // prevent conflict
52371 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52373 else { // panel object assumed!
52378 * Adds a xtype elements to the layout.
52382 xtype : 'ContentPanel',
52389 xtype : 'NestedLayoutPanel',
52395 items : [ ... list of content panels or nested layout panels.. ]
52399 * @param {Object} cfg Xtype definition of item to add.
52401 addxtype : function(cfg)
52403 // basically accepts a pannel...
52404 // can accept a layout region..!?!?
52405 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52407 if (!cfg.xtype.match(/Panel$/)) {
52412 if (typeof(cfg.region) == 'undefined') {
52413 Roo.log("Failed to add Panel, region was not set");
52417 var region = cfg.region;
52423 xitems = cfg.items;
52430 case 'ContentPanel': // ContentPanel (el, cfg)
52431 case 'ScrollPanel': // ContentPanel (el, cfg)
52433 if(cfg.autoCreate) {
52434 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52436 var el = this.el.createChild();
52437 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52440 this.add(region, ret);
52444 case 'TreePanel': // our new panel!
52445 cfg.el = this.el.createChild();
52446 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52447 this.add(region, ret);
52450 case 'NestedLayoutPanel':
52451 // create a new Layout (which is a Border Layout...
52452 var el = this.el.createChild();
52453 var clayout = cfg.layout;
52455 clayout.items = clayout.items || [];
52456 // replace this exitems with the clayout ones..
52457 xitems = clayout.items;
52460 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52461 cfg.background = false;
52463 var layout = new Roo.BorderLayout(el, clayout);
52465 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52466 //console.log('adding nested layout panel ' + cfg.toSource());
52467 this.add(region, ret);
52468 nb = {}; /// find first...
52473 // needs grid and region
52475 //var el = this.getRegion(region).el.createChild();
52476 var el = this.el.createChild();
52477 // create the grid first...
52479 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52481 if (region == 'center' && this.active ) {
52482 cfg.background = false;
52484 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52486 this.add(region, ret);
52487 if (cfg.background) {
52488 ret.on('activate', function(gp) {
52489 if (!gp.grid.rendered) {
52504 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52506 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52507 this.add(region, ret);
52510 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52514 // GridPanel (grid, cfg)
52517 this.beginUpdate();
52521 Roo.each(xitems, function(i) {
52522 region = nb && i.region ? i.region : false;
52524 var add = ret.addxtype(i);
52527 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52528 if (!i.background) {
52529 abn[region] = nb[region] ;
52536 // make the last non-background panel active..
52537 //if (nb) { Roo.log(abn); }
52540 for(var r in abn) {
52541 region = this.getRegion(r);
52543 // tried using nb[r], but it does not work..
52545 region.showPanel(abn[r]);
52556 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52557 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52558 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52559 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52562 var CP = Roo.ContentPanel;
52564 var layout = Roo.BorderLayout.create({
52568 panels: [new CP("north", "North")]
52577 panels: [new CP("west", {title: "West"})]
52586 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52595 panels: [new CP("south", {title: "South", closable: true})]
52602 preferredTabWidth: 150,
52604 new CP("center1", {title: "Close Me", closable: true}),
52605 new CP("center2", {title: "Center Panel", closable: false})
52610 layout.getRegion("center").showPanel("center1");
52615 Roo.BorderLayout.create = function(config, targetEl){
52616 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52617 layout.beginUpdate();
52618 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52619 for(var j = 0, jlen = regions.length; j < jlen; j++){
52620 var lr = regions[j];
52621 if(layout.regions[lr] && config[lr].panels){
52622 var r = layout.regions[lr];
52623 var ps = config[lr].panels;
52624 layout.addTypedPanels(r, ps);
52627 layout.endUpdate();
52632 Roo.BorderLayout.RegionFactory = {
52634 validRegions : ["north","south","east","west","center"],
52637 create : function(target, mgr, config){
52638 target = target.toLowerCase();
52639 if(config.lightweight || config.basic){
52640 return new Roo.BasicLayoutRegion(mgr, config, target);
52644 return new Roo.NorthLayoutRegion(mgr, config);
52646 return new Roo.SouthLayoutRegion(mgr, config);
52648 return new Roo.EastLayoutRegion(mgr, config);
52650 return new Roo.WestLayoutRegion(mgr, config);
52652 return new Roo.CenterLayoutRegion(mgr, config);
52654 throw 'Layout region "'+target+'" not supported.';
52658 * Ext JS Library 1.1.1
52659 * Copyright(c) 2006-2007, Ext JS, LLC.
52661 * Originally Released Under LGPL - original licence link has changed is not relivant.
52664 * <script type="text/javascript">
52668 * @class Roo.BasicLayoutRegion
52669 * @extends Roo.util.Observable
52670 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52671 * and does not have a titlebar, tabs or any other features. All it does is size and position
52672 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52674 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52676 this.position = pos;
52679 * @scope Roo.BasicLayoutRegion
52683 * @event beforeremove
52684 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52685 * @param {Roo.LayoutRegion} this
52686 * @param {Roo.ContentPanel} panel The panel
52687 * @param {Object} e The cancel event object
52689 "beforeremove" : true,
52691 * @event invalidated
52692 * Fires when the layout for this region is changed.
52693 * @param {Roo.LayoutRegion} this
52695 "invalidated" : true,
52697 * @event visibilitychange
52698 * Fires when this region is shown or hidden
52699 * @param {Roo.LayoutRegion} this
52700 * @param {Boolean} visibility true or false
52702 "visibilitychange" : true,
52704 * @event paneladded
52705 * Fires when a panel is added.
52706 * @param {Roo.LayoutRegion} this
52707 * @param {Roo.ContentPanel} panel The panel
52709 "paneladded" : true,
52711 * @event panelremoved
52712 * Fires when a panel is removed.
52713 * @param {Roo.LayoutRegion} this
52714 * @param {Roo.ContentPanel} panel The panel
52716 "panelremoved" : true,
52718 * @event beforecollapse
52719 * Fires when this region before collapse.
52720 * @param {Roo.LayoutRegion} this
52722 "beforecollapse" : true,
52725 * Fires when this region is collapsed.
52726 * @param {Roo.LayoutRegion} this
52728 "collapsed" : true,
52731 * Fires when this region is expanded.
52732 * @param {Roo.LayoutRegion} this
52737 * Fires when this region is slid into view.
52738 * @param {Roo.LayoutRegion} this
52740 "slideshow" : true,
52743 * Fires when this region slides out of view.
52744 * @param {Roo.LayoutRegion} this
52746 "slidehide" : true,
52748 * @event panelactivated
52749 * Fires when a panel is activated.
52750 * @param {Roo.LayoutRegion} this
52751 * @param {Roo.ContentPanel} panel The activated panel
52753 "panelactivated" : true,
52756 * Fires when the user resizes this region.
52757 * @param {Roo.LayoutRegion} this
52758 * @param {Number} newSize The new size (width for east/west, height for north/south)
52762 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52763 this.panels = new Roo.util.MixedCollection();
52764 this.panels.getKey = this.getPanelId.createDelegate(this);
52766 this.activePanel = null;
52767 // ensure listeners are added...
52769 if (config.listeners || config.events) {
52770 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52771 listeners : config.listeners || {},
52772 events : config.events || {}
52776 if(skipConfig !== true){
52777 this.applyConfig(config);
52781 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52782 getPanelId : function(p){
52786 applyConfig : function(config){
52787 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52788 this.config = config;
52793 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
52794 * the width, for horizontal (north, south) the height.
52795 * @param {Number} newSize The new width or height
52797 resizeTo : function(newSize){
52798 var el = this.el ? this.el :
52799 (this.activePanel ? this.activePanel.getEl() : null);
52801 switch(this.position){
52804 el.setWidth(newSize);
52805 this.fireEvent("resized", this, newSize);
52809 el.setHeight(newSize);
52810 this.fireEvent("resized", this, newSize);
52816 getBox : function(){
52817 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
52820 getMargins : function(){
52821 return this.margins;
52824 updateBox : function(box){
52826 var el = this.activePanel.getEl();
52827 el.dom.style.left = box.x + "px";
52828 el.dom.style.top = box.y + "px";
52829 this.activePanel.setSize(box.width, box.height);
52833 * Returns the container element for this region.
52834 * @return {Roo.Element}
52836 getEl : function(){
52837 return this.activePanel;
52841 * Returns true if this region is currently visible.
52842 * @return {Boolean}
52844 isVisible : function(){
52845 return this.activePanel ? true : false;
52848 setActivePanel : function(panel){
52849 panel = this.getPanel(panel);
52850 if(this.activePanel && this.activePanel != panel){
52851 this.activePanel.setActiveState(false);
52852 this.activePanel.getEl().setLeftTop(-10000,-10000);
52854 this.activePanel = panel;
52855 panel.setActiveState(true);
52857 panel.setSize(this.box.width, this.box.height);
52859 this.fireEvent("panelactivated", this, panel);
52860 this.fireEvent("invalidated");
52864 * Show the specified panel.
52865 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
52866 * @return {Roo.ContentPanel} The shown panel or null
52868 showPanel : function(panel){
52869 if(panel = this.getPanel(panel)){
52870 this.setActivePanel(panel);
52876 * Get the active panel for this region.
52877 * @return {Roo.ContentPanel} The active panel or null
52879 getActivePanel : function(){
52880 return this.activePanel;
52884 * Add the passed ContentPanel(s)
52885 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52886 * @return {Roo.ContentPanel} The panel added (if only one was added)
52888 add : function(panel){
52889 if(arguments.length > 1){
52890 for(var i = 0, len = arguments.length; i < len; i++) {
52891 this.add(arguments[i]);
52895 if(this.hasPanel(panel)){
52896 this.showPanel(panel);
52899 var el = panel.getEl();
52900 if(el.dom.parentNode != this.mgr.el.dom){
52901 this.mgr.el.dom.appendChild(el.dom);
52903 if(panel.setRegion){
52904 panel.setRegion(this);
52906 this.panels.add(panel);
52907 el.setStyle("position", "absolute");
52908 if(!panel.background){
52909 this.setActivePanel(panel);
52910 if(this.config.initialSize && this.panels.getCount()==1){
52911 this.resizeTo(this.config.initialSize);
52914 this.fireEvent("paneladded", this, panel);
52919 * Returns true if the panel is in this region.
52920 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52921 * @return {Boolean}
52923 hasPanel : function(panel){
52924 if(typeof panel == "object"){ // must be panel obj
52925 panel = panel.getId();
52927 return this.getPanel(panel) ? true : false;
52931 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52932 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52933 * @param {Boolean} preservePanel Overrides the config preservePanel option
52934 * @return {Roo.ContentPanel} The panel that was removed
52936 remove : function(panel, preservePanel){
52937 panel = this.getPanel(panel);
52942 this.fireEvent("beforeremove", this, panel, e);
52943 if(e.cancel === true){
52946 var panelId = panel.getId();
52947 this.panels.removeKey(panelId);
52952 * Returns the panel specified or null if it's not in this region.
52953 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52954 * @return {Roo.ContentPanel}
52956 getPanel : function(id){
52957 if(typeof id == "object"){ // must be panel obj
52960 return this.panels.get(id);
52964 * Returns this regions position (north/south/east/west/center).
52967 getPosition: function(){
52968 return this.position;
52972 * Ext JS Library 1.1.1
52973 * Copyright(c) 2006-2007, Ext JS, LLC.
52975 * Originally Released Under LGPL - original licence link has changed is not relivant.
52978 * <script type="text/javascript">
52982 * @class Roo.LayoutRegion
52983 * @extends Roo.BasicLayoutRegion
52984 * This class represents a region in a layout manager.
52985 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
52986 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
52987 * @cfg {Boolean} floatable False to disable floating (defaults to true)
52988 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
52989 * @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})
52990 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
52991 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
52992 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
52993 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
52994 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
52995 * @cfg {String} title The title for the region (overrides panel titles)
52996 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
52997 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
52998 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
52999 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
53000 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
53001 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
53002 * the space available, similar to FireFox 1.5 tabs (defaults to false)
53003 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
53004 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
53005 * @cfg {Boolean} showPin True to show a pin button
53006 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
53007 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
53008 * @cfg {Boolean} disableTabTips True to disable tab tooltips
53009 * @cfg {Number} width For East/West panels
53010 * @cfg {Number} height For North/South panels
53011 * @cfg {Boolean} split To show the splitter
53012 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
53014 Roo.LayoutRegion = function(mgr, config, pos){
53015 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
53016 var dh = Roo.DomHelper;
53017 /** This region's container element
53018 * @type Roo.Element */
53019 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
53020 /** This region's title element
53021 * @type Roo.Element */
53023 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
53024 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
53025 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
53027 this.titleEl.enableDisplayMode();
53028 /** This region's title text element
53029 * @type HTMLElement */
53030 this.titleTextEl = this.titleEl.dom.firstChild;
53031 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53032 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53033 this.closeBtn.enableDisplayMode();
53034 this.closeBtn.on("click", this.closeClicked, this);
53035 this.closeBtn.hide();
53037 this.createBody(config);
53038 this.visible = true;
53039 this.collapsed = false;
53041 if(config.hideWhenEmpty){
53043 this.on("paneladded", this.validateVisibility, this);
53044 this.on("panelremoved", this.validateVisibility, this);
53046 this.applyConfig(config);
53049 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53051 createBody : function(){
53052 /** This region's body element
53053 * @type Roo.Element */
53054 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53057 applyConfig : function(c){
53058 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53059 var dh = Roo.DomHelper;
53060 if(c.titlebar !== false){
53061 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53062 this.collapseBtn.on("click", this.collapse, this);
53063 this.collapseBtn.enableDisplayMode();
53065 if(c.showPin === true || this.showPin){
53066 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53067 this.stickBtn.enableDisplayMode();
53068 this.stickBtn.on("click", this.expand, this);
53069 this.stickBtn.hide();
53072 /** This region's collapsed element
53073 * @type Roo.Element */
53074 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53075 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53077 if(c.floatable !== false){
53078 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53079 this.collapsedEl.on("click", this.collapseClick, this);
53082 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53083 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53084 id: "message", unselectable: "on", style:{"float":"left"}});
53085 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53087 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53088 this.expandBtn.on("click", this.expand, this);
53090 if(this.collapseBtn){
53091 this.collapseBtn.setVisible(c.collapsible == true);
53093 this.cmargins = c.cmargins || this.cmargins ||
53094 (this.position == "west" || this.position == "east" ?
53095 {top: 0, left: 2, right:2, bottom: 0} :
53096 {top: 2, left: 0, right:0, bottom: 2});
53097 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53098 this.bottomTabs = c.tabPosition != "top";
53099 this.autoScroll = c.autoScroll || false;
53100 if(this.autoScroll){
53101 this.bodyEl.setStyle("overflow", "auto");
53103 this.bodyEl.setStyle("overflow", "hidden");
53105 //if(c.titlebar !== false){
53106 if((!c.titlebar && !c.title) || c.titlebar === false){
53107 this.titleEl.hide();
53109 this.titleEl.show();
53111 this.titleTextEl.innerHTML = c.title;
53115 this.duration = c.duration || .30;
53116 this.slideDuration = c.slideDuration || .45;
53119 this.collapse(true);
53126 * Returns true if this region is currently visible.
53127 * @return {Boolean}
53129 isVisible : function(){
53130 return this.visible;
53134 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53135 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53137 setCollapsedTitle : function(title){
53138 title = title || " ";
53139 if(this.collapsedTitleTextEl){
53140 this.collapsedTitleTextEl.innerHTML = title;
53144 getBox : function(){
53146 if(!this.collapsed){
53147 b = this.el.getBox(false, true);
53149 b = this.collapsedEl.getBox(false, true);
53154 getMargins : function(){
53155 return this.collapsed ? this.cmargins : this.margins;
53158 highlight : function(){
53159 this.el.addClass("x-layout-panel-dragover");
53162 unhighlight : function(){
53163 this.el.removeClass("x-layout-panel-dragover");
53166 updateBox : function(box){
53168 if(!this.collapsed){
53169 this.el.dom.style.left = box.x + "px";
53170 this.el.dom.style.top = box.y + "px";
53171 this.updateBody(box.width, box.height);
53173 this.collapsedEl.dom.style.left = box.x + "px";
53174 this.collapsedEl.dom.style.top = box.y + "px";
53175 this.collapsedEl.setSize(box.width, box.height);
53178 this.tabs.autoSizeTabs();
53182 updateBody : function(w, h){
53184 this.el.setWidth(w);
53185 w -= this.el.getBorderWidth("rl");
53186 if(this.config.adjustments){
53187 w += this.config.adjustments[0];
53191 this.el.setHeight(h);
53192 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53193 h -= this.el.getBorderWidth("tb");
53194 if(this.config.adjustments){
53195 h += this.config.adjustments[1];
53197 this.bodyEl.setHeight(h);
53199 h = this.tabs.syncHeight(h);
53202 if(this.panelSize){
53203 w = w !== null ? w : this.panelSize.width;
53204 h = h !== null ? h : this.panelSize.height;
53206 if(this.activePanel){
53207 var el = this.activePanel.getEl();
53208 w = w !== null ? w : el.getWidth();
53209 h = h !== null ? h : el.getHeight();
53210 this.panelSize = {width: w, height: h};
53211 this.activePanel.setSize(w, h);
53213 if(Roo.isIE && this.tabs){
53214 this.tabs.el.repaint();
53219 * Returns the container element for this region.
53220 * @return {Roo.Element}
53222 getEl : function(){
53227 * Hides this region.
53230 if(!this.collapsed){
53231 this.el.dom.style.left = "-2000px";
53234 this.collapsedEl.dom.style.left = "-2000px";
53235 this.collapsedEl.hide();
53237 this.visible = false;
53238 this.fireEvent("visibilitychange", this, false);
53242 * Shows this region if it was previously hidden.
53245 if(!this.collapsed){
53248 this.collapsedEl.show();
53250 this.visible = true;
53251 this.fireEvent("visibilitychange", this, true);
53254 closeClicked : function(){
53255 if(this.activePanel){
53256 this.remove(this.activePanel);
53260 collapseClick : function(e){
53262 e.stopPropagation();
53265 e.stopPropagation();
53271 * Collapses this region.
53272 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53274 collapse : function(skipAnim, skipCheck){
53275 if(this.collapsed) {
53279 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53281 this.collapsed = true;
53283 this.split.el.hide();
53285 if(this.config.animate && skipAnim !== true){
53286 this.fireEvent("invalidated", this);
53287 this.animateCollapse();
53289 this.el.setLocation(-20000,-20000);
53291 this.collapsedEl.show();
53292 this.fireEvent("collapsed", this);
53293 this.fireEvent("invalidated", this);
53299 animateCollapse : function(){
53304 * Expands this region if it was previously collapsed.
53305 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53306 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53308 expand : function(e, skipAnim){
53310 e.stopPropagation();
53312 if(!this.collapsed || this.el.hasActiveFx()) {
53316 this.afterSlideIn();
53319 this.collapsed = false;
53320 if(this.config.animate && skipAnim !== true){
53321 this.animateExpand();
53325 this.split.el.show();
53327 this.collapsedEl.setLocation(-2000,-2000);
53328 this.collapsedEl.hide();
53329 this.fireEvent("invalidated", this);
53330 this.fireEvent("expanded", this);
53334 animateExpand : function(){
53338 initTabs : function()
53340 this.bodyEl.setStyle("overflow", "hidden");
53341 var ts = new Roo.TabPanel(
53344 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53345 disableTooltips: this.config.disableTabTips,
53346 toolbar : this.config.toolbar
53349 if(this.config.hideTabs){
53350 ts.stripWrap.setDisplayed(false);
53353 ts.resizeTabs = this.config.resizeTabs === true;
53354 ts.minTabWidth = this.config.minTabWidth || 40;
53355 ts.maxTabWidth = this.config.maxTabWidth || 250;
53356 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53357 ts.monitorResize = false;
53358 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53359 ts.bodyEl.addClass('x-layout-tabs-body');
53360 this.panels.each(this.initPanelAsTab, this);
53363 initPanelAsTab : function(panel){
53364 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53365 this.config.closeOnTab && panel.isClosable());
53366 if(panel.tabTip !== undefined){
53367 ti.setTooltip(panel.tabTip);
53369 ti.on("activate", function(){
53370 this.setActivePanel(panel);
53372 if(this.config.closeOnTab){
53373 ti.on("beforeclose", function(t, e){
53375 this.remove(panel);
53381 updatePanelTitle : function(panel, title){
53382 if(this.activePanel == panel){
53383 this.updateTitle(title);
53386 var ti = this.tabs.getTab(panel.getEl().id);
53388 if(panel.tabTip !== undefined){
53389 ti.setTooltip(panel.tabTip);
53394 updateTitle : function(title){
53395 if(this.titleTextEl && !this.config.title){
53396 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53400 setActivePanel : function(panel){
53401 panel = this.getPanel(panel);
53402 if(this.activePanel && this.activePanel != panel){
53403 this.activePanel.setActiveState(false);
53405 this.activePanel = panel;
53406 panel.setActiveState(true);
53407 if(this.panelSize){
53408 panel.setSize(this.panelSize.width, this.panelSize.height);
53411 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53413 this.updateTitle(panel.getTitle());
53415 this.fireEvent("invalidated", this);
53417 this.fireEvent("panelactivated", this, panel);
53421 * Shows the specified panel.
53422 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53423 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53425 showPanel : function(panel)
53427 panel = this.getPanel(panel);
53430 var tab = this.tabs.getTab(panel.getEl().id);
53431 if(tab.isHidden()){
53432 this.tabs.unhideTab(tab.id);
53436 this.setActivePanel(panel);
53443 * Get the active panel for this region.
53444 * @return {Roo.ContentPanel} The active panel or null
53446 getActivePanel : function(){
53447 return this.activePanel;
53450 validateVisibility : function(){
53451 if(this.panels.getCount() < 1){
53452 this.updateTitle(" ");
53453 this.closeBtn.hide();
53456 if(!this.isVisible()){
53463 * Adds the passed ContentPanel(s) to this region.
53464 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53465 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53467 add : function(panel){
53468 if(arguments.length > 1){
53469 for(var i = 0, len = arguments.length; i < len; i++) {
53470 this.add(arguments[i]);
53474 if(this.hasPanel(panel)){
53475 this.showPanel(panel);
53478 panel.setRegion(this);
53479 this.panels.add(panel);
53480 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53481 this.bodyEl.dom.appendChild(panel.getEl().dom);
53482 if(panel.background !== true){
53483 this.setActivePanel(panel);
53485 this.fireEvent("paneladded", this, panel);
53491 this.initPanelAsTab(panel);
53493 if(panel.background !== true){
53494 this.tabs.activate(panel.getEl().id);
53496 this.fireEvent("paneladded", this, panel);
53501 * Hides the tab for the specified panel.
53502 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53504 hidePanel : function(panel){
53505 if(this.tabs && (panel = this.getPanel(panel))){
53506 this.tabs.hideTab(panel.getEl().id);
53511 * Unhides the tab for a previously hidden panel.
53512 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53514 unhidePanel : function(panel){
53515 if(this.tabs && (panel = this.getPanel(panel))){
53516 this.tabs.unhideTab(panel.getEl().id);
53520 clearPanels : function(){
53521 while(this.panels.getCount() > 0){
53522 this.remove(this.panels.first());
53527 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53528 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53529 * @param {Boolean} preservePanel Overrides the config preservePanel option
53530 * @return {Roo.ContentPanel} The panel that was removed
53532 remove : function(panel, preservePanel){
53533 panel = this.getPanel(panel);
53538 this.fireEvent("beforeremove", this, panel, e);
53539 if(e.cancel === true){
53542 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53543 var panelId = panel.getId();
53544 this.panels.removeKey(panelId);
53546 document.body.appendChild(panel.getEl().dom);
53549 this.tabs.removeTab(panel.getEl().id);
53550 }else if (!preservePanel){
53551 this.bodyEl.dom.removeChild(panel.getEl().dom);
53553 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53554 var p = this.panels.first();
53555 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53556 tempEl.appendChild(p.getEl().dom);
53557 this.bodyEl.update("");
53558 this.bodyEl.dom.appendChild(p.getEl().dom);
53560 this.updateTitle(p.getTitle());
53562 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53563 this.setActivePanel(p);
53565 panel.setRegion(null);
53566 if(this.activePanel == panel){
53567 this.activePanel = null;
53569 if(this.config.autoDestroy !== false && preservePanel !== true){
53570 try{panel.destroy();}catch(e){}
53572 this.fireEvent("panelremoved", this, panel);
53577 * Returns the TabPanel component used by this region
53578 * @return {Roo.TabPanel}
53580 getTabs : function(){
53584 createTool : function(parentEl, className){
53585 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53586 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53587 btn.addClassOnOver("x-layout-tools-button-over");
53592 * Ext JS Library 1.1.1
53593 * Copyright(c) 2006-2007, Ext JS, LLC.
53595 * Originally Released Under LGPL - original licence link has changed is not relivant.
53598 * <script type="text/javascript">
53604 * @class Roo.SplitLayoutRegion
53605 * @extends Roo.LayoutRegion
53606 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53608 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53609 this.cursor = cursor;
53610 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53613 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53614 splitTip : "Drag to resize.",
53615 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53616 useSplitTips : false,
53618 applyConfig : function(config){
53619 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53622 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53623 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53624 /** The SplitBar for this region
53625 * @type Roo.SplitBar */
53626 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53627 this.split.on("moved", this.onSplitMove, this);
53628 this.split.useShim = config.useShim === true;
53629 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53630 if(this.useSplitTips){
53631 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53633 if(config.collapsible){
53634 this.split.el.on("dblclick", this.collapse, this);
53637 if(typeof config.minSize != "undefined"){
53638 this.split.minSize = config.minSize;
53640 if(typeof config.maxSize != "undefined"){
53641 this.split.maxSize = config.maxSize;
53643 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53644 this.hideSplitter();
53649 getHMaxSize : function(){
53650 var cmax = this.config.maxSize || 10000;
53651 var center = this.mgr.getRegion("center");
53652 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53655 getVMaxSize : function(){
53656 var cmax = this.config.maxSize || 10000;
53657 var center = this.mgr.getRegion("center");
53658 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53661 onSplitMove : function(split, newSize){
53662 this.fireEvent("resized", this, newSize);
53666 * Returns the {@link Roo.SplitBar} for this region.
53667 * @return {Roo.SplitBar}
53669 getSplitBar : function(){
53674 this.hideSplitter();
53675 Roo.SplitLayoutRegion.superclass.hide.call(this);
53678 hideSplitter : function(){
53680 this.split.el.setLocation(-2000,-2000);
53681 this.split.el.hide();
53687 this.split.el.show();
53689 Roo.SplitLayoutRegion.superclass.show.call(this);
53692 beforeSlide: function(){
53693 if(Roo.isGecko){// firefox overflow auto bug workaround
53694 this.bodyEl.clip();
53696 this.tabs.bodyEl.clip();
53698 if(this.activePanel){
53699 this.activePanel.getEl().clip();
53701 if(this.activePanel.beforeSlide){
53702 this.activePanel.beforeSlide();
53708 afterSlide : function(){
53709 if(Roo.isGecko){// firefox overflow auto bug workaround
53710 this.bodyEl.unclip();
53712 this.tabs.bodyEl.unclip();
53714 if(this.activePanel){
53715 this.activePanel.getEl().unclip();
53716 if(this.activePanel.afterSlide){
53717 this.activePanel.afterSlide();
53723 initAutoHide : function(){
53724 if(this.autoHide !== false){
53725 if(!this.autoHideHd){
53726 var st = new Roo.util.DelayedTask(this.slideIn, this);
53727 this.autoHideHd = {
53728 "mouseout": function(e){
53729 if(!e.within(this.el, true)){
53733 "mouseover" : function(e){
53739 this.el.on(this.autoHideHd);
53743 clearAutoHide : function(){
53744 if(this.autoHide !== false){
53745 this.el.un("mouseout", this.autoHideHd.mouseout);
53746 this.el.un("mouseover", this.autoHideHd.mouseover);
53750 clearMonitor : function(){
53751 Roo.get(document).un("click", this.slideInIf, this);
53754 // these names are backwards but not changed for compat
53755 slideOut : function(){
53756 if(this.isSlid || this.el.hasActiveFx()){
53759 this.isSlid = true;
53760 if(this.collapseBtn){
53761 this.collapseBtn.hide();
53763 this.closeBtnState = this.closeBtn.getStyle('display');
53764 this.closeBtn.hide();
53766 this.stickBtn.show();
53769 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53770 this.beforeSlide();
53771 this.el.setStyle("z-index", 10001);
53772 this.el.slideIn(this.getSlideAnchor(), {
53773 callback: function(){
53775 this.initAutoHide();
53776 Roo.get(document).on("click", this.slideInIf, this);
53777 this.fireEvent("slideshow", this);
53784 afterSlideIn : function(){
53785 this.clearAutoHide();
53786 this.isSlid = false;
53787 this.clearMonitor();
53788 this.el.setStyle("z-index", "");
53789 if(this.collapseBtn){
53790 this.collapseBtn.show();
53792 this.closeBtn.setStyle('display', this.closeBtnState);
53794 this.stickBtn.hide();
53796 this.fireEvent("slidehide", this);
53799 slideIn : function(cb){
53800 if(!this.isSlid || this.el.hasActiveFx()){
53804 this.isSlid = false;
53805 this.beforeSlide();
53806 this.el.slideOut(this.getSlideAnchor(), {
53807 callback: function(){
53808 this.el.setLeftTop(-10000, -10000);
53810 this.afterSlideIn();
53818 slideInIf : function(e){
53819 if(!e.within(this.el)){
53824 animateCollapse : function(){
53825 this.beforeSlide();
53826 this.el.setStyle("z-index", 20000);
53827 var anchor = this.getSlideAnchor();
53828 this.el.slideOut(anchor, {
53829 callback : function(){
53830 this.el.setStyle("z-index", "");
53831 this.collapsedEl.slideIn(anchor, {duration:.3});
53833 this.el.setLocation(-10000,-10000);
53835 this.fireEvent("collapsed", this);
53842 animateExpand : function(){
53843 this.beforeSlide();
53844 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
53845 this.el.setStyle("z-index", 20000);
53846 this.collapsedEl.hide({
53849 this.el.slideIn(this.getSlideAnchor(), {
53850 callback : function(){
53851 this.el.setStyle("z-index", "");
53854 this.split.el.show();
53856 this.fireEvent("invalidated", this);
53857 this.fireEvent("expanded", this);
53885 getAnchor : function(){
53886 return this.anchors[this.position];
53889 getCollapseAnchor : function(){
53890 return this.canchors[this.position];
53893 getSlideAnchor : function(){
53894 return this.sanchors[this.position];
53897 getAlignAdj : function(){
53898 var cm = this.cmargins;
53899 switch(this.position){
53915 getExpandAdj : function(){
53916 var c = this.collapsedEl, cm = this.cmargins;
53917 switch(this.position){
53919 return [-(cm.right+c.getWidth()+cm.left), 0];
53922 return [cm.right+c.getWidth()+cm.left, 0];
53925 return [0, -(cm.top+cm.bottom+c.getHeight())];
53928 return [0, cm.top+cm.bottom+c.getHeight()];
53934 * Ext JS Library 1.1.1
53935 * Copyright(c) 2006-2007, Ext JS, LLC.
53937 * Originally Released Under LGPL - original licence link has changed is not relivant.
53940 * <script type="text/javascript">
53943 * These classes are private internal classes
53945 Roo.CenterLayoutRegion = function(mgr, config){
53946 Roo.LayoutRegion.call(this, mgr, config, "center");
53947 this.visible = true;
53948 this.minWidth = config.minWidth || 20;
53949 this.minHeight = config.minHeight || 20;
53952 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
53954 // center panel can't be hidden
53958 // center panel can't be hidden
53961 getMinWidth: function(){
53962 return this.minWidth;
53965 getMinHeight: function(){
53966 return this.minHeight;
53971 Roo.NorthLayoutRegion = function(mgr, config){
53972 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
53974 this.split.placement = Roo.SplitBar.TOP;
53975 this.split.orientation = Roo.SplitBar.VERTICAL;
53976 this.split.el.addClass("x-layout-split-v");
53978 var size = config.initialSize || config.height;
53979 if(typeof size != "undefined"){
53980 this.el.setHeight(size);
53983 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
53984 orientation: Roo.SplitBar.VERTICAL,
53985 getBox : function(){
53986 if(this.collapsed){
53987 return this.collapsedEl.getBox();
53989 var box = this.el.getBox();
53991 box.height += this.split.el.getHeight();
53996 updateBox : function(box){
53997 if(this.split && !this.collapsed){
53998 box.height -= this.split.el.getHeight();
53999 this.split.el.setLeft(box.x);
54000 this.split.el.setTop(box.y+box.height);
54001 this.split.el.setWidth(box.width);
54003 if(this.collapsed){
54004 this.updateBody(box.width, null);
54006 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54010 Roo.SouthLayoutRegion = function(mgr, config){
54011 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
54013 this.split.placement = Roo.SplitBar.BOTTOM;
54014 this.split.orientation = Roo.SplitBar.VERTICAL;
54015 this.split.el.addClass("x-layout-split-v");
54017 var size = config.initialSize || config.height;
54018 if(typeof size != "undefined"){
54019 this.el.setHeight(size);
54022 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
54023 orientation: Roo.SplitBar.VERTICAL,
54024 getBox : function(){
54025 if(this.collapsed){
54026 return this.collapsedEl.getBox();
54028 var box = this.el.getBox();
54030 var sh = this.split.el.getHeight();
54037 updateBox : function(box){
54038 if(this.split && !this.collapsed){
54039 var sh = this.split.el.getHeight();
54042 this.split.el.setLeft(box.x);
54043 this.split.el.setTop(box.y-sh);
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.EastLayoutRegion = function(mgr, config){
54054 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54056 this.split.placement = Roo.SplitBar.RIGHT;
54057 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54058 this.split.el.addClass("x-layout-split-h");
54060 var size = config.initialSize || config.width;
54061 if(typeof size != "undefined"){
54062 this.el.setWidth(size);
54065 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54066 orientation: Roo.SplitBar.HORIZONTAL,
54067 getBox : function(){
54068 if(this.collapsed){
54069 return this.collapsedEl.getBox();
54071 var box = this.el.getBox();
54073 var sw = this.split.el.getWidth();
54080 updateBox : function(box){
54081 if(this.split && !this.collapsed){
54082 var sw = this.split.el.getWidth();
54084 this.split.el.setLeft(box.x);
54085 this.split.el.setTop(box.y);
54086 this.split.el.setHeight(box.height);
54089 if(this.collapsed){
54090 this.updateBody(null, box.height);
54092 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54096 Roo.WestLayoutRegion = function(mgr, config){
54097 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54099 this.split.placement = Roo.SplitBar.LEFT;
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.WestLayoutRegion, 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 box.width += this.split.el.getWidth();
54121 updateBox : function(box){
54122 if(this.split && !this.collapsed){
54123 var sw = this.split.el.getWidth();
54125 this.split.el.setLeft(box.x+box.width);
54126 this.split.el.setTop(box.y);
54127 this.split.el.setHeight(box.height);
54129 if(this.collapsed){
54130 this.updateBody(null, box.height);
54132 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54137 * Ext JS Library 1.1.1
54138 * Copyright(c) 2006-2007, Ext JS, LLC.
54140 * Originally Released Under LGPL - original licence link has changed is not relivant.
54143 * <script type="text/javascript">
54148 * Private internal class for reading and applying state
54150 Roo.LayoutStateManager = function(layout){
54151 // default empty state
54160 Roo.LayoutStateManager.prototype = {
54161 init : function(layout, provider){
54162 this.provider = provider;
54163 var state = provider.get(layout.id+"-layout-state");
54165 var wasUpdating = layout.isUpdating();
54167 layout.beginUpdate();
54169 for(var key in state){
54170 if(typeof state[key] != "function"){
54171 var rstate = state[key];
54172 var r = layout.getRegion(key);
54175 r.resizeTo(rstate.size);
54177 if(rstate.collapsed == true){
54180 r.expand(null, true);
54186 layout.endUpdate();
54188 this.state = state;
54190 this.layout = layout;
54191 layout.on("regionresized", this.onRegionResized, this);
54192 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54193 layout.on("regionexpanded", this.onRegionExpanded, this);
54196 storeState : function(){
54197 this.provider.set(this.layout.id+"-layout-state", this.state);
54200 onRegionResized : function(region, newSize){
54201 this.state[region.getPosition()].size = newSize;
54205 onRegionCollapsed : function(region){
54206 this.state[region.getPosition()].collapsed = true;
54210 onRegionExpanded : function(region){
54211 this.state[region.getPosition()].collapsed = false;
54216 * Ext JS Library 1.1.1
54217 * Copyright(c) 2006-2007, Ext JS, LLC.
54219 * Originally Released Under LGPL - original licence link has changed is not relivant.
54222 * <script type="text/javascript">
54225 * @class Roo.ContentPanel
54226 * @extends Roo.util.Observable
54227 * A basic ContentPanel element.
54228 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54229 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54230 * @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
54231 * @cfg {Boolean} closable True if the panel can be closed/removed
54232 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54233 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54234 * @cfg {Toolbar} toolbar A toolbar for this panel
54235 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54236 * @cfg {String} title The title for this panel
54237 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54238 * @cfg {String} url Calls {@link #setUrl} with this value
54239 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54240 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54241 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54242 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54243 * @cfg {String} style Extra style to add to the content panel
54246 * Create a new ContentPanel.
54247 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54248 * @param {String/Object} config A string to set only the title or a config object
54249 * @param {String} content (optional) Set the HTML content for this panel
54250 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54252 Roo.ContentPanel = function(el, config, content){
54256 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54260 if (config && config.parentLayout) {
54261 el = config.parentLayout.el.createChild();
54264 if(el.autoCreate){ // xtype is available if this is called from factory
54268 this.el = Roo.get(el);
54269 if(!this.el && config && config.autoCreate){
54270 if(typeof config.autoCreate == "object"){
54271 if(!config.autoCreate.id){
54272 config.autoCreate.id = config.id||el;
54274 this.el = Roo.DomHelper.append(document.body,
54275 config.autoCreate, true);
54277 this.el = Roo.DomHelper.append(document.body,
54278 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54283 this.closable = false;
54284 this.loaded = false;
54285 this.active = false;
54286 if(typeof config == "string"){
54287 this.title = config;
54289 Roo.apply(this, config);
54292 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54293 this.wrapEl = this.el.wrap();
54294 this.toolbar.container = this.el.insertSibling(false, 'before');
54295 this.toolbar = new Roo.Toolbar(this.toolbar);
54298 // xtype created footer. - not sure if will work as we normally have to render first..
54299 if (this.footer && !this.footer.el && this.footer.xtype) {
54300 if (!this.wrapEl) {
54301 this.wrapEl = this.el.wrap();
54304 this.footer.container = this.wrapEl.createChild();
54306 this.footer = Roo.factory(this.footer, Roo);
54311 this.resizeEl = Roo.get(this.resizeEl, true);
54313 this.resizeEl = this.el;
54315 // handle view.xtype
54323 * Fires when this panel is activated.
54324 * @param {Roo.ContentPanel} this
54328 * @event deactivate
54329 * Fires when this panel is activated.
54330 * @param {Roo.ContentPanel} this
54332 "deactivate" : true,
54336 * Fires when this panel is resized if fitToFrame is true.
54337 * @param {Roo.ContentPanel} this
54338 * @param {Number} width The width after any component adjustments
54339 * @param {Number} height The height after any component adjustments
54345 * Fires when this tab is created
54346 * @param {Roo.ContentPanel} this
54356 if(this.autoScroll){
54357 this.resizeEl.setStyle("overflow", "auto");
54359 // fix randome scrolling
54360 this.el.on('scroll', function() {
54361 Roo.log('fix random scolling');
54362 this.scrollTo('top',0);
54365 content = content || this.content;
54367 this.setContent(content);
54369 if(config && config.url){
54370 this.setUrl(this.url, this.params, this.loadOnce);
54375 Roo.ContentPanel.superclass.constructor.call(this);
54377 if (this.view && typeof(this.view.xtype) != 'undefined') {
54378 this.view.el = this.el.appendChild(document.createElement("div"));
54379 this.view = Roo.factory(this.view);
54380 this.view.render && this.view.render(false, '');
54384 this.fireEvent('render', this);
54387 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54389 setRegion : function(region){
54390 this.region = region;
54392 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54394 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54399 * Returns the toolbar for this Panel if one was configured.
54400 * @return {Roo.Toolbar}
54402 getToolbar : function(){
54403 return this.toolbar;
54406 setActiveState : function(active){
54407 this.active = active;
54409 this.fireEvent("deactivate", this);
54411 this.fireEvent("activate", this);
54415 * Updates this panel's element
54416 * @param {String} content The new content
54417 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54419 setContent : function(content, loadScripts){
54420 this.el.update(content, loadScripts);
54423 ignoreResize : function(w, h){
54424 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54427 this.lastSize = {width: w, height: h};
54432 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54433 * @return {Roo.UpdateManager} The UpdateManager
54435 getUpdateManager : function(){
54436 return this.el.getUpdateManager();
54439 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54440 * @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:
54443 url: "your-url.php",
54444 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54445 callback: yourFunction,
54446 scope: yourObject, //(optional scope)
54449 text: "Loading...",
54454 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54455 * 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.
54456 * @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}
54457 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54458 * @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.
54459 * @return {Roo.ContentPanel} this
54462 var um = this.el.getUpdateManager();
54463 um.update.apply(um, arguments);
54469 * 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.
54470 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54471 * @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)
54472 * @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)
54473 * @return {Roo.UpdateManager} The UpdateManager
54475 setUrl : function(url, params, loadOnce){
54476 if(this.refreshDelegate){
54477 this.removeListener("activate", this.refreshDelegate);
54479 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54480 this.on("activate", this.refreshDelegate);
54481 return this.el.getUpdateManager();
54484 _handleRefresh : function(url, params, loadOnce){
54485 if(!loadOnce || !this.loaded){
54486 var updater = this.el.getUpdateManager();
54487 updater.update(url, params, this._setLoaded.createDelegate(this));
54491 _setLoaded : function(){
54492 this.loaded = true;
54496 * Returns this panel's id
54499 getId : function(){
54504 * Returns this panel's element - used by regiosn to add.
54505 * @return {Roo.Element}
54507 getEl : function(){
54508 return this.wrapEl || this.el;
54511 adjustForComponents : function(width, height)
54513 //Roo.log('adjustForComponents ');
54514 if(this.resizeEl != this.el){
54515 width -= this.el.getFrameWidth('lr');
54516 height -= this.el.getFrameWidth('tb');
54519 var te = this.toolbar.getEl();
54520 height -= te.getHeight();
54521 te.setWidth(width);
54524 var te = this.footer.getEl();
54525 //Roo.log("footer:" + te.getHeight());
54527 height -= te.getHeight();
54528 te.setWidth(width);
54532 if(this.adjustments){
54533 width += this.adjustments[0];
54534 height += this.adjustments[1];
54536 return {"width": width, "height": height};
54539 setSize : function(width, height){
54540 if(this.fitToFrame && !this.ignoreResize(width, height)){
54541 if(this.fitContainer && this.resizeEl != this.el){
54542 this.el.setSize(width, height);
54544 var size = this.adjustForComponents(width, height);
54545 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54546 this.fireEvent('resize', this, size.width, size.height);
54551 * Returns this panel's title
54554 getTitle : function(){
54559 * Set this panel's title
54560 * @param {String} title
54562 setTitle : function(title){
54563 this.title = title;
54565 this.region.updatePanelTitle(this, title);
54570 * Returns true is this panel was configured to be closable
54571 * @return {Boolean}
54573 isClosable : function(){
54574 return this.closable;
54577 beforeSlide : function(){
54579 this.resizeEl.clip();
54582 afterSlide : function(){
54584 this.resizeEl.unclip();
54588 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54589 * Will fail silently if the {@link #setUrl} method has not been called.
54590 * This does not activate the panel, just updates its content.
54592 refresh : function(){
54593 if(this.refreshDelegate){
54594 this.loaded = false;
54595 this.refreshDelegate();
54600 * Destroys this panel
54602 destroy : function(){
54603 this.el.removeAllListeners();
54604 var tempEl = document.createElement("span");
54605 tempEl.appendChild(this.el.dom);
54606 tempEl.innerHTML = "";
54612 * form - if the content panel contains a form - this is a reference to it.
54613 * @type {Roo.form.Form}
54617 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54618 * This contains a reference to it.
54624 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54634 * @param {Object} cfg Xtype definition of item to add.
54637 addxtype : function(cfg) {
54639 if (cfg.xtype.match(/^Form$/)) {
54642 //if (this.footer) {
54643 // el = this.footer.container.insertSibling(false, 'before');
54645 el = this.el.createChild();
54648 this.form = new Roo.form.Form(cfg);
54651 if ( this.form.allItems.length) {
54652 this.form.render(el.dom);
54656 // should only have one of theses..
54657 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54658 // views.. should not be just added - used named prop 'view''
54660 cfg.el = this.el.appendChild(document.createElement("div"));
54663 var ret = new Roo.factory(cfg);
54665 ret.render && ret.render(false, ''); // render blank..
54674 * @class Roo.GridPanel
54675 * @extends Roo.ContentPanel
54677 * Create a new GridPanel.
54678 * @param {Roo.grid.Grid} grid The grid for this panel
54679 * @param {String/Object} config A string to set only the panel's title, or a config object
54681 Roo.GridPanel = function(grid, config){
54684 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54685 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54687 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54689 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54692 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54694 // xtype created footer. - not sure if will work as we normally have to render first..
54695 if (this.footer && !this.footer.el && this.footer.xtype) {
54697 this.footer.container = this.grid.getView().getFooterPanel(true);
54698 this.footer.dataSource = this.grid.dataSource;
54699 this.footer = Roo.factory(this.footer, Roo);
54703 grid.monitorWindowResize = false; // turn off autosizing
54704 grid.autoHeight = false;
54705 grid.autoWidth = false;
54707 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54710 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54711 getId : function(){
54712 return this.grid.id;
54716 * Returns the grid for this panel
54717 * @return {Roo.grid.Grid}
54719 getGrid : function(){
54723 setSize : function(width, height){
54724 if(!this.ignoreResize(width, height)){
54725 var grid = this.grid;
54726 var size = this.adjustForComponents(width, height);
54727 grid.getGridEl().setSize(size.width, size.height);
54732 beforeSlide : function(){
54733 this.grid.getView().scroller.clip();
54736 afterSlide : function(){
54737 this.grid.getView().scroller.unclip();
54740 destroy : function(){
54741 this.grid.destroy();
54743 Roo.GridPanel.superclass.destroy.call(this);
54749 * @class Roo.NestedLayoutPanel
54750 * @extends Roo.ContentPanel
54752 * Create a new NestedLayoutPanel.
54755 * @param {Roo.BorderLayout} layout The layout for this panel
54756 * @param {String/Object} config A string to set only the title or a config object
54758 Roo.NestedLayoutPanel = function(layout, config)
54760 // construct with only one argument..
54761 /* FIXME - implement nicer consturctors
54762 if (layout.layout) {
54764 layout = config.layout;
54765 delete config.layout;
54767 if (layout.xtype && !layout.getEl) {
54768 // then layout needs constructing..
54769 layout = Roo.factory(layout, Roo);
54774 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54776 layout.monitorWindowResize = false; // turn off autosizing
54777 this.layout = layout;
54778 this.layout.getEl().addClass("x-layout-nested-layout");
54785 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
54787 setSize : function(width, height){
54788 if(!this.ignoreResize(width, height)){
54789 var size = this.adjustForComponents(width, height);
54790 var el = this.layout.getEl();
54791 el.setSize(size.width, size.height);
54792 var touch = el.dom.offsetWidth;
54793 this.layout.layout();
54794 // ie requires a double layout on the first pass
54795 if(Roo.isIE && !this.initialized){
54796 this.initialized = true;
54797 this.layout.layout();
54802 // activate all subpanels if not currently active..
54804 setActiveState : function(active){
54805 this.active = active;
54807 this.fireEvent("deactivate", this);
54811 this.fireEvent("activate", this);
54812 // not sure if this should happen before or after..
54813 if (!this.layout) {
54814 return; // should not happen..
54817 for (var r in this.layout.regions) {
54818 reg = this.layout.getRegion(r);
54819 if (reg.getActivePanel()) {
54820 //reg.showPanel(reg.getActivePanel()); // force it to activate..
54821 reg.setActivePanel(reg.getActivePanel());
54824 if (!reg.panels.length) {
54827 reg.showPanel(reg.getPanel(0));
54836 * Returns the nested BorderLayout for this panel
54837 * @return {Roo.BorderLayout}
54839 getLayout : function(){
54840 return this.layout;
54844 * Adds a xtype elements to the layout of the nested panel
54848 xtype : 'ContentPanel',
54855 xtype : 'NestedLayoutPanel',
54861 items : [ ... list of content panels or nested layout panels.. ]
54865 * @param {Object} cfg Xtype definition of item to add.
54867 addxtype : function(cfg) {
54868 return this.layout.addxtype(cfg);
54873 Roo.ScrollPanel = function(el, config, content){
54874 config = config || {};
54875 config.fitToFrame = true;
54876 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
54878 this.el.dom.style.overflow = "hidden";
54879 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
54880 this.el.removeClass("x-layout-inactive-content");
54881 this.el.on("mousewheel", this.onWheel, this);
54883 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
54884 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
54885 up.unselectable(); down.unselectable();
54886 up.on("click", this.scrollUp, this);
54887 down.on("click", this.scrollDown, this);
54888 up.addClassOnOver("x-scroller-btn-over");
54889 down.addClassOnOver("x-scroller-btn-over");
54890 up.addClassOnClick("x-scroller-btn-click");
54891 down.addClassOnClick("x-scroller-btn-click");
54892 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
54894 this.resizeEl = this.el;
54895 this.el = wrap; this.up = up; this.down = down;
54898 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
54900 wheelIncrement : 5,
54901 scrollUp : function(){
54902 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
54905 scrollDown : function(){
54906 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
54909 afterScroll : function(){
54910 var el = this.resizeEl;
54911 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
54912 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54913 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54916 setSize : function(){
54917 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
54918 this.afterScroll();
54921 onWheel : function(e){
54922 var d = e.getWheelDelta();
54923 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
54924 this.afterScroll();
54928 setContent : function(content, loadScripts){
54929 this.resizeEl.update(content, loadScripts);
54943 * @class Roo.TreePanel
54944 * @extends Roo.ContentPanel
54946 * Create a new TreePanel. - defaults to fit/scoll contents.
54947 * @param {String/Object} config A string to set only the panel's title, or a config object
54948 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
54950 Roo.TreePanel = function(config){
54951 var el = config.el;
54952 var tree = config.tree;
54953 delete config.tree;
54954 delete config.el; // hopefull!
54956 // wrapper for IE7 strict & safari scroll issue
54958 var treeEl = el.createChild();
54959 config.resizeEl = treeEl;
54963 Roo.TreePanel.superclass.constructor.call(this, el, config);
54966 this.tree = new Roo.tree.TreePanel(treeEl , tree);
54967 //console.log(tree);
54968 this.on('activate', function()
54970 if (this.tree.rendered) {
54973 //console.log('render tree');
54974 this.tree.render();
54976 // this should not be needed.. - it's actually the 'el' that resizes?
54977 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
54979 //this.on('resize', function (cp, w, h) {
54980 // this.tree.innerCt.setWidth(w);
54981 // this.tree.innerCt.setHeight(h);
54982 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
54989 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
55006 * Ext JS Library 1.1.1
55007 * Copyright(c) 2006-2007, Ext JS, LLC.
55009 * Originally Released Under LGPL - original licence link has changed is not relivant.
55012 * <script type="text/javascript">
55017 * @class Roo.ReaderLayout
55018 * @extends Roo.BorderLayout
55019 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
55020 * center region containing two nested regions (a top one for a list view and one for item preview below),
55021 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
55022 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
55023 * expedites the setup of the overall layout and regions for this common application style.
55026 var reader = new Roo.ReaderLayout();
55027 var CP = Roo.ContentPanel; // shortcut for adding
55029 reader.beginUpdate();
55030 reader.add("north", new CP("north", "North"));
55031 reader.add("west", new CP("west", {title: "West"}));
55032 reader.add("east", new CP("east", {title: "East"}));
55034 reader.regions.listView.add(new CP("listView", "List"));
55035 reader.regions.preview.add(new CP("preview", "Preview"));
55036 reader.endUpdate();
55039 * Create a new ReaderLayout
55040 * @param {Object} config Configuration options
55041 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55042 * document.body if omitted)
55044 Roo.ReaderLayout = function(config, renderTo){
55045 var c = config || {size:{}};
55046 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55047 north: c.north !== false ? Roo.apply({
55051 }, c.north) : false,
55052 west: c.west !== false ? Roo.apply({
55060 margins:{left:5,right:0,bottom:5,top:5},
55061 cmargins:{left:5,right:5,bottom:5,top:5}
55062 }, c.west) : false,
55063 east: c.east !== false ? Roo.apply({
55071 margins:{left:0,right:5,bottom:5,top:5},
55072 cmargins:{left:5,right:5,bottom:5,top:5}
55073 }, c.east) : false,
55074 center: Roo.apply({
55075 tabPosition: 'top',
55079 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55083 this.el.addClass('x-reader');
55085 this.beginUpdate();
55087 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55088 south: c.preview !== false ? Roo.apply({
55095 cmargins:{top:5,left:0, right:0, bottom:0}
55096 }, c.preview) : false,
55097 center: Roo.apply({
55103 this.add('center', new Roo.NestedLayoutPanel(inner,
55104 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55108 this.regions.preview = inner.getRegion('south');
55109 this.regions.listView = inner.getRegion('center');
55112 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55114 * Ext JS Library 1.1.1
55115 * Copyright(c) 2006-2007, Ext JS, LLC.
55117 * Originally Released Under LGPL - original licence link has changed is not relivant.
55120 * <script type="text/javascript">
55124 * @class Roo.grid.Grid
55125 * @extends Roo.util.Observable
55126 * This class represents the primary interface of a component based grid control.
55127 * <br><br>Usage:<pre><code>
55128 var grid = new Roo.grid.Grid("my-container-id", {
55131 selModel: mySelectionModel,
55132 autoSizeColumns: true,
55133 monitorWindowResize: false,
55134 trackMouseOver: true
55139 * <b>Common Problems:</b><br/>
55140 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55141 * element will correct this<br/>
55142 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55143 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55144 * are unpredictable.<br/>
55145 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55146 * grid to calculate dimensions/offsets.<br/>
55148 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55149 * The container MUST have some type of size defined for the grid to fill. The container will be
55150 * automatically set to position relative if it isn't already.
55151 * @param {Object} config A config object that sets properties on this grid.
55153 Roo.grid.Grid = function(container, config){
55154 // initialize the container
55155 this.container = Roo.get(container);
55156 this.container.update("");
55157 this.container.setStyle("overflow", "hidden");
55158 this.container.addClass('x-grid-container');
55160 this.id = this.container.id;
55162 Roo.apply(this, config);
55163 // check and correct shorthanded configs
55165 this.dataSource = this.ds;
55169 this.colModel = this.cm;
55173 this.selModel = this.sm;
55177 if (this.selModel) {
55178 this.selModel = Roo.factory(this.selModel, Roo.grid);
55179 this.sm = this.selModel;
55180 this.sm.xmodule = this.xmodule || false;
55182 if (typeof(this.colModel.config) == 'undefined') {
55183 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55184 this.cm = this.colModel;
55185 this.cm.xmodule = this.xmodule || false;
55187 if (this.dataSource) {
55188 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55189 this.ds = this.dataSource;
55190 this.ds.xmodule = this.xmodule || false;
55197 this.container.setWidth(this.width);
55201 this.container.setHeight(this.height);
55208 * The raw click event for the entire grid.
55209 * @param {Roo.EventObject} e
55214 * The raw dblclick event for the entire grid.
55215 * @param {Roo.EventObject} e
55219 * @event contextmenu
55220 * The raw contextmenu event for the entire grid.
55221 * @param {Roo.EventObject} e
55223 "contextmenu" : true,
55226 * The raw mousedown event for the entire grid.
55227 * @param {Roo.EventObject} e
55229 "mousedown" : true,
55232 * The raw mouseup event for the entire grid.
55233 * @param {Roo.EventObject} e
55238 * The raw mouseover event for the entire grid.
55239 * @param {Roo.EventObject} e
55241 "mouseover" : true,
55244 * The raw mouseout event for the entire grid.
55245 * @param {Roo.EventObject} e
55250 * The raw keypress event for the entire grid.
55251 * @param {Roo.EventObject} e
55256 * The raw keydown event for the entire grid.
55257 * @param {Roo.EventObject} e
55265 * Fires when a cell is clicked
55266 * @param {Grid} this
55267 * @param {Number} rowIndex
55268 * @param {Number} columnIndex
55269 * @param {Roo.EventObject} e
55271 "cellclick" : true,
55273 * @event celldblclick
55274 * Fires when a cell is double clicked
55275 * @param {Grid} this
55276 * @param {Number} rowIndex
55277 * @param {Number} columnIndex
55278 * @param {Roo.EventObject} e
55280 "celldblclick" : true,
55283 * Fires when a row is clicked
55284 * @param {Grid} this
55285 * @param {Number} rowIndex
55286 * @param {Roo.EventObject} e
55290 * @event rowdblclick
55291 * Fires when a row is double clicked
55292 * @param {Grid} this
55293 * @param {Number} rowIndex
55294 * @param {Roo.EventObject} e
55296 "rowdblclick" : true,
55298 * @event headerclick
55299 * Fires when a header is clicked
55300 * @param {Grid} this
55301 * @param {Number} columnIndex
55302 * @param {Roo.EventObject} e
55304 "headerclick" : true,
55306 * @event headerdblclick
55307 * Fires when a header cell is double clicked
55308 * @param {Grid} this
55309 * @param {Number} columnIndex
55310 * @param {Roo.EventObject} e
55312 "headerdblclick" : true,
55314 * @event rowcontextmenu
55315 * Fires when a row is right clicked
55316 * @param {Grid} this
55317 * @param {Number} rowIndex
55318 * @param {Roo.EventObject} e
55320 "rowcontextmenu" : true,
55322 * @event cellcontextmenu
55323 * Fires when a cell is right clicked
55324 * @param {Grid} this
55325 * @param {Number} rowIndex
55326 * @param {Number} cellIndex
55327 * @param {Roo.EventObject} e
55329 "cellcontextmenu" : true,
55331 * @event headercontextmenu
55332 * Fires when a header is right clicked
55333 * @param {Grid} this
55334 * @param {Number} columnIndex
55335 * @param {Roo.EventObject} e
55337 "headercontextmenu" : true,
55339 * @event bodyscroll
55340 * Fires when the body element is scrolled
55341 * @param {Number} scrollLeft
55342 * @param {Number} scrollTop
55344 "bodyscroll" : true,
55346 * @event columnresize
55347 * Fires when the user resizes a column
55348 * @param {Number} columnIndex
55349 * @param {Number} newSize
55351 "columnresize" : true,
55353 * @event columnmove
55354 * Fires when the user moves a column
55355 * @param {Number} oldIndex
55356 * @param {Number} newIndex
55358 "columnmove" : true,
55361 * Fires when row(s) start being dragged
55362 * @param {Grid} this
55363 * @param {Roo.GridDD} dd The drag drop object
55364 * @param {event} e The raw browser event
55366 "startdrag" : true,
55369 * Fires when a drag operation is complete
55370 * @param {Grid} this
55371 * @param {Roo.GridDD} dd The drag drop object
55372 * @param {event} e The raw browser event
55377 * Fires when dragged row(s) are dropped on a valid DD target
55378 * @param {Grid} this
55379 * @param {Roo.GridDD} dd The drag drop object
55380 * @param {String} targetId The target drag drop object
55381 * @param {event} e The raw browser event
55386 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55387 * @param {Grid} this
55388 * @param {Roo.GridDD} dd The drag drop object
55389 * @param {String} targetId The target drag drop object
55390 * @param {event} e The raw browser event
55395 * Fires when the dragged row(s) first cross another DD target while being dragged
55396 * @param {Grid} this
55397 * @param {Roo.GridDD} dd The drag drop object
55398 * @param {String} targetId The target drag drop object
55399 * @param {event} e The raw browser event
55401 "dragenter" : true,
55404 * Fires when the dragged row(s) leave another DD target while being dragged
55405 * @param {Grid} this
55406 * @param {Roo.GridDD} dd The drag drop object
55407 * @param {String} targetId The target drag drop object
55408 * @param {event} e The raw browser event
55413 * Fires when a row is rendered, so you can change add a style to it.
55414 * @param {GridView} gridview The grid view
55415 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55421 * Fires when the grid is rendered
55422 * @param {Grid} grid
55427 Roo.grid.Grid.superclass.constructor.call(this);
55429 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55432 * @cfg {String} ddGroup - drag drop group.
55435 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
55439 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55441 minColumnWidth : 25,
55444 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55445 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55446 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55448 autoSizeColumns : false,
55451 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55453 autoSizeHeaders : true,
55456 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55458 monitorWindowResize : true,
55461 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55462 * rows measured to get a columns size. Default is 0 (all rows).
55464 maxRowsToMeasure : 0,
55467 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55469 trackMouseOver : true,
55472 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55475 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
55479 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55481 enableDragDrop : false,
55484 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55486 enableColumnMove : true,
55489 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55491 enableColumnHide : true,
55494 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55496 enableRowHeightSync : false,
55499 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55504 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55506 autoHeight : false,
55509 * @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.
55511 autoExpandColumn : false,
55514 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55517 autoExpandMin : 50,
55520 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55522 autoExpandMax : 1000,
55525 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55530 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55534 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55544 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55545 * of a fixed width. Default is false.
55548 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55553 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55554 * %0 is replaced with the number of selected rows.
55556 ddText : "{0} selected row{1}",
55560 * Called once after all setup has been completed and the grid is ready to be rendered.
55561 * @return {Roo.grid.Grid} this
55563 render : function()
55565 var c = this.container;
55566 // try to detect autoHeight/width mode
55567 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55568 this.autoHeight = true;
55570 var view = this.getView();
55573 c.on("click", this.onClick, this);
55574 c.on("dblclick", this.onDblClick, this);
55575 c.on("contextmenu", this.onContextMenu, this);
55576 c.on("keydown", this.onKeyDown, this);
55578 c.on("touchstart", this.onTouchStart, this);
55581 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55583 this.getSelectionModel().init(this);
55588 this.loadMask = new Roo.LoadMask(this.container,
55589 Roo.apply({store:this.dataSource}, this.loadMask));
55593 if (this.toolbar && this.toolbar.xtype) {
55594 this.toolbar.container = this.getView().getHeaderPanel(true);
55595 this.toolbar = new Roo.Toolbar(this.toolbar);
55597 if (this.footer && this.footer.xtype) {
55598 this.footer.dataSource = this.getDataSource();
55599 this.footer.container = this.getView().getFooterPanel(true);
55600 this.footer = Roo.factory(this.footer, Roo);
55602 if (this.dropTarget && this.dropTarget.xtype) {
55603 delete this.dropTarget.xtype;
55604 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55608 this.rendered = true;
55609 this.fireEvent('render', this);
55614 * Reconfigures the grid to use a different Store and Column Model.
55615 * The View will be bound to the new objects and refreshed.
55616 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55617 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55619 reconfigure : function(dataSource, colModel){
55621 this.loadMask.destroy();
55622 this.loadMask = new Roo.LoadMask(this.container,
55623 Roo.apply({store:dataSource}, this.loadMask));
55625 this.view.bind(dataSource, colModel);
55626 this.dataSource = dataSource;
55627 this.colModel = colModel;
55628 this.view.refresh(true);
55632 * Add's a column, default at the end..
55634 * @param {int} position to add (default end)
55635 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55637 addColumns : function(pos, ar)
55640 for (var i =0;i< ar.length;i++) {
55642 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55643 this.cm.lookup[cfg.id] = cfg;
55647 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55648 pos = this.cm.config.length; //this.cm.config.push(cfg);
55650 pos = Math.max(0,pos);
55653 this.cm.config.splice.apply(this.cm.config, ar);
55657 this.view.generateRules(this.cm);
55658 this.view.refresh(true);
55666 onKeyDown : function(e){
55667 this.fireEvent("keydown", e);
55671 * Destroy this grid.
55672 * @param {Boolean} removeEl True to remove the element
55674 destroy : function(removeEl, keepListeners){
55676 this.loadMask.destroy();
55678 var c = this.container;
55679 c.removeAllListeners();
55680 this.view.destroy();
55681 this.colModel.purgeListeners();
55682 if(!keepListeners){
55683 this.purgeListeners();
55686 if(removeEl === true){
55692 processEvent : function(name, e){
55693 // does this fire select???
55694 //Roo.log('grid:processEvent ' + name);
55696 if (name != 'touchstart' ) {
55697 this.fireEvent(name, e);
55700 var t = e.getTarget();
55702 var header = v.findHeaderIndex(t);
55703 if(header !== false){
55704 var ename = name == 'touchstart' ? 'click' : name;
55706 this.fireEvent("header" + ename, this, header, e);
55708 var row = v.findRowIndex(t);
55709 var cell = v.findCellIndex(t);
55710 if (name == 'touchstart') {
55711 // first touch is always a click.
55712 // hopefull this happens after selection is updated.?
55715 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55716 var cs = this.selModel.getSelectedCell();
55717 if (row == cs[0] && cell == cs[1]){
55721 if (typeof(this.selModel.getSelections) != 'undefined') {
55722 var cs = this.selModel.getSelections();
55723 var ds = this.dataSource;
55724 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55735 this.fireEvent("row" + name, this, row, e);
55736 if(cell !== false){
55737 this.fireEvent("cell" + name, this, row, cell, e);
55744 onClick : function(e){
55745 this.processEvent("click", e);
55748 onTouchStart : function(e){
55749 this.processEvent("touchstart", e);
55753 onContextMenu : function(e, t){
55754 this.processEvent("contextmenu", e);
55758 onDblClick : function(e){
55759 this.processEvent("dblclick", e);
55763 walkCells : function(row, col, step, fn, scope){
55764 var cm = this.colModel, clen = cm.getColumnCount();
55765 var ds = this.dataSource, rlen = ds.getCount(), first = true;
55777 if(fn.call(scope || this, row, col, cm) === true){
55795 if(fn.call(scope || this, row, col, cm) === true){
55807 getSelections : function(){
55808 return this.selModel.getSelections();
55812 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
55813 * but if manual update is required this method will initiate it.
55815 autoSize : function(){
55817 this.view.layout();
55818 if(this.view.adjustForScroll){
55819 this.view.adjustForScroll();
55825 * Returns the grid's underlying element.
55826 * @return {Element} The element
55828 getGridEl : function(){
55829 return this.container;
55832 // private for compatibility, overridden by editor grid
55833 stopEditing : function(){},
55836 * Returns the grid's SelectionModel.
55837 * @return {SelectionModel}
55839 getSelectionModel : function(){
55840 if(!this.selModel){
55841 this.selModel = new Roo.grid.RowSelectionModel();
55843 return this.selModel;
55847 * Returns the grid's DataSource.
55848 * @return {DataSource}
55850 getDataSource : function(){
55851 return this.dataSource;
55855 * Returns the grid's ColumnModel.
55856 * @return {ColumnModel}
55858 getColumnModel : function(){
55859 return this.colModel;
55863 * Returns the grid's GridView object.
55864 * @return {GridView}
55866 getView : function(){
55868 this.view = new Roo.grid.GridView(this.viewConfig);
55869 this.relayEvents(this.view, [
55870 "beforerowremoved", "beforerowsinserted",
55871 "beforerefresh", "rowremoved",
55872 "rowsinserted", "rowupdated" ,"refresh"
55878 * Called to get grid's drag proxy text, by default returns this.ddText.
55879 * Override this to put something different in the dragged text.
55882 getDragDropText : function(){
55883 var count = this.selModel.getCount();
55884 return String.format(this.ddText, count, count == 1 ? '' : 's');
55889 * Ext JS Library 1.1.1
55890 * Copyright(c) 2006-2007, Ext JS, LLC.
55892 * Originally Released Under LGPL - original licence link has changed is not relivant.
55895 * <script type="text/javascript">
55898 Roo.grid.AbstractGridView = function(){
55902 "beforerowremoved" : true,
55903 "beforerowsinserted" : true,
55904 "beforerefresh" : true,
55905 "rowremoved" : true,
55906 "rowsinserted" : true,
55907 "rowupdated" : true,
55910 Roo.grid.AbstractGridView.superclass.constructor.call(this);
55913 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
55914 rowClass : "x-grid-row",
55915 cellClass : "x-grid-cell",
55916 tdClass : "x-grid-td",
55917 hdClass : "x-grid-hd",
55918 splitClass : "x-grid-hd-split",
55920 init: function(grid){
55922 var cid = this.grid.getGridEl().id;
55923 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
55924 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
55925 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
55926 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
55929 getColumnRenderers : function(){
55930 var renderers = [];
55931 var cm = this.grid.colModel;
55932 var colCount = cm.getColumnCount();
55933 for(var i = 0; i < colCount; i++){
55934 renderers[i] = cm.getRenderer(i);
55939 getColumnIds : function(){
55941 var cm = this.grid.colModel;
55942 var colCount = cm.getColumnCount();
55943 for(var i = 0; i < colCount; i++){
55944 ids[i] = cm.getColumnId(i);
55949 getDataIndexes : function(){
55950 if(!this.indexMap){
55951 this.indexMap = this.buildIndexMap();
55953 return this.indexMap.colToData;
55956 getColumnIndexByDataIndex : function(dataIndex){
55957 if(!this.indexMap){
55958 this.indexMap = this.buildIndexMap();
55960 return this.indexMap.dataToCol[dataIndex];
55964 * Set a css style for a column dynamically.
55965 * @param {Number} colIndex The index of the column
55966 * @param {String} name The css property name
55967 * @param {String} value The css value
55969 setCSSStyle : function(colIndex, name, value){
55970 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
55971 Roo.util.CSS.updateRule(selector, name, value);
55974 generateRules : function(cm){
55975 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
55976 Roo.util.CSS.removeStyleSheet(rulesId);
55977 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55978 var cid = cm.getColumnId(i);
55979 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
55980 this.tdSelector, cid, " {\n}\n",
55981 this.hdSelector, cid, " {\n}\n",
55982 this.splitSelector, cid, " {\n}\n");
55984 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55988 * Ext JS Library 1.1.1
55989 * Copyright(c) 2006-2007, Ext JS, LLC.
55991 * Originally Released Under LGPL - original licence link has changed is not relivant.
55994 * <script type="text/javascript">
55998 // This is a support class used internally by the Grid components
55999 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
56001 this.view = grid.getView();
56002 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56003 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
56005 this.setHandleElId(Roo.id(hd));
56006 this.setOuterHandleElId(Roo.id(hd2));
56008 this.scroll = false;
56010 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
56012 getDragData : function(e){
56013 var t = Roo.lib.Event.getTarget(e);
56014 var h = this.view.findHeaderCell(t);
56016 return {ddel: h.firstChild, header:h};
56021 onInitDrag : function(e){
56022 this.view.headersDisabled = true;
56023 var clone = this.dragData.ddel.cloneNode(true);
56024 clone.id = Roo.id();
56025 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
56026 this.proxy.update(clone);
56030 afterValidDrop : function(){
56032 setTimeout(function(){
56033 v.headersDisabled = false;
56037 afterInvalidDrop : function(){
56039 setTimeout(function(){
56040 v.headersDisabled = false;
56046 * Ext JS Library 1.1.1
56047 * Copyright(c) 2006-2007, Ext JS, LLC.
56049 * Originally Released Under LGPL - original licence link has changed is not relivant.
56052 * <script type="text/javascript">
56055 // This is a support class used internally by the Grid components
56056 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56058 this.view = grid.getView();
56059 // split the proxies so they don't interfere with mouse events
56060 this.proxyTop = Roo.DomHelper.append(document.body, {
56061 cls:"col-move-top", html:" "
56063 this.proxyBottom = Roo.DomHelper.append(document.body, {
56064 cls:"col-move-bottom", html:" "
56066 this.proxyTop.hide = this.proxyBottom.hide = function(){
56067 this.setLeftTop(-100,-100);
56068 this.setStyle("visibility", "hidden");
56070 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56071 // temporarily disabled
56072 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56073 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56075 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56076 proxyOffsets : [-4, -9],
56077 fly: Roo.Element.fly,
56079 getTargetFromEvent : function(e){
56080 var t = Roo.lib.Event.getTarget(e);
56081 var cindex = this.view.findCellIndex(t);
56082 if(cindex !== false){
56083 return this.view.getHeaderCell(cindex);
56088 nextVisible : function(h){
56089 var v = this.view, cm = this.grid.colModel;
56092 if(!cm.isHidden(v.getCellIndex(h))){
56100 prevVisible : function(h){
56101 var v = this.view, cm = this.grid.colModel;
56104 if(!cm.isHidden(v.getCellIndex(h))){
56112 positionIndicator : function(h, n, e){
56113 var x = Roo.lib.Event.getPageX(e);
56114 var r = Roo.lib.Dom.getRegion(n.firstChild);
56115 var px, pt, py = r.top + this.proxyOffsets[1];
56116 if((r.right - x) <= (r.right-r.left)/2){
56117 px = r.right+this.view.borderWidth;
56123 var oldIndex = this.view.getCellIndex(h);
56124 var newIndex = this.view.getCellIndex(n);
56126 if(this.grid.colModel.isFixed(newIndex)){
56130 var locked = this.grid.colModel.isLocked(newIndex);
56135 if(oldIndex < newIndex){
56138 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56141 px += this.proxyOffsets[0];
56142 this.proxyTop.setLeftTop(px, py);
56143 this.proxyTop.show();
56144 if(!this.bottomOffset){
56145 this.bottomOffset = this.view.mainHd.getHeight();
56147 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56148 this.proxyBottom.show();
56152 onNodeEnter : function(n, dd, e, data){
56153 if(data.header != n){
56154 this.positionIndicator(data.header, n, e);
56158 onNodeOver : function(n, dd, e, data){
56159 var result = false;
56160 if(data.header != n){
56161 result = this.positionIndicator(data.header, n, e);
56164 this.proxyTop.hide();
56165 this.proxyBottom.hide();
56167 return result ? this.dropAllowed : this.dropNotAllowed;
56170 onNodeOut : function(n, dd, e, data){
56171 this.proxyTop.hide();
56172 this.proxyBottom.hide();
56175 onNodeDrop : function(n, dd, e, data){
56176 var h = data.header;
56178 var cm = this.grid.colModel;
56179 var x = Roo.lib.Event.getPageX(e);
56180 var r = Roo.lib.Dom.getRegion(n.firstChild);
56181 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56182 var oldIndex = this.view.getCellIndex(h);
56183 var newIndex = this.view.getCellIndex(n);
56184 var locked = cm.isLocked(newIndex);
56188 if(oldIndex < newIndex){
56191 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56194 cm.setLocked(oldIndex, locked, true);
56195 cm.moveColumn(oldIndex, newIndex);
56196 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56204 * Ext JS Library 1.1.1
56205 * Copyright(c) 2006-2007, Ext JS, LLC.
56207 * Originally Released Under LGPL - original licence link has changed is not relivant.
56210 * <script type="text/javascript">
56214 * @class Roo.grid.GridView
56215 * @extends Roo.util.Observable
56218 * @param {Object} config
56220 Roo.grid.GridView = function(config){
56221 Roo.grid.GridView.superclass.constructor.call(this);
56224 Roo.apply(this, config);
56227 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56229 unselectable : 'unselectable="on"',
56230 unselectableCls : 'x-unselectable',
56233 rowClass : "x-grid-row",
56235 cellClass : "x-grid-col",
56237 tdClass : "x-grid-td",
56239 hdClass : "x-grid-hd",
56241 splitClass : "x-grid-split",
56243 sortClasses : ["sort-asc", "sort-desc"],
56245 enableMoveAnim : false,
56249 dh : Roo.DomHelper,
56251 fly : Roo.Element.fly,
56253 css : Roo.util.CSS,
56259 scrollIncrement : 22,
56261 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56263 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56265 bind : function(ds, cm){
56267 this.ds.un("load", this.onLoad, this);
56268 this.ds.un("datachanged", this.onDataChange, this);
56269 this.ds.un("add", this.onAdd, this);
56270 this.ds.un("remove", this.onRemove, this);
56271 this.ds.un("update", this.onUpdate, this);
56272 this.ds.un("clear", this.onClear, this);
56275 ds.on("load", this.onLoad, this);
56276 ds.on("datachanged", this.onDataChange, this);
56277 ds.on("add", this.onAdd, this);
56278 ds.on("remove", this.onRemove, this);
56279 ds.on("update", this.onUpdate, this);
56280 ds.on("clear", this.onClear, this);
56285 this.cm.un("widthchange", this.onColWidthChange, this);
56286 this.cm.un("headerchange", this.onHeaderChange, this);
56287 this.cm.un("hiddenchange", this.onHiddenChange, this);
56288 this.cm.un("columnmoved", this.onColumnMove, this);
56289 this.cm.un("columnlockchange", this.onColumnLock, this);
56292 this.generateRules(cm);
56293 cm.on("widthchange", this.onColWidthChange, this);
56294 cm.on("headerchange", this.onHeaderChange, this);
56295 cm.on("hiddenchange", this.onHiddenChange, this);
56296 cm.on("columnmoved", this.onColumnMove, this);
56297 cm.on("columnlockchange", this.onColumnLock, this);
56302 init: function(grid){
56303 Roo.grid.GridView.superclass.init.call(this, grid);
56305 this.bind(grid.dataSource, grid.colModel);
56307 grid.on("headerclick", this.handleHeaderClick, this);
56309 if(grid.trackMouseOver){
56310 grid.on("mouseover", this.onRowOver, this);
56311 grid.on("mouseout", this.onRowOut, this);
56313 grid.cancelTextSelection = function(){};
56314 this.gridId = grid.id;
56316 var tpls = this.templates || {};
56319 tpls.master = new Roo.Template(
56320 '<div class="x-grid" hidefocus="true">',
56321 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56322 '<div class="x-grid-topbar"></div>',
56323 '<div class="x-grid-scroller"><div></div></div>',
56324 '<div class="x-grid-locked">',
56325 '<div class="x-grid-header">{lockedHeader}</div>',
56326 '<div class="x-grid-body">{lockedBody}</div>',
56328 '<div class="x-grid-viewport">',
56329 '<div class="x-grid-header">{header}</div>',
56330 '<div class="x-grid-body">{body}</div>',
56332 '<div class="x-grid-bottombar"></div>',
56334 '<div class="x-grid-resize-proxy"> </div>',
56337 tpls.master.disableformats = true;
56341 tpls.header = new Roo.Template(
56342 '<table border="0" cellspacing="0" cellpadding="0">',
56343 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56346 tpls.header.disableformats = true;
56348 tpls.header.compile();
56351 tpls.hcell = new Roo.Template(
56352 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56353 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56356 tpls.hcell.disableFormats = true;
56358 tpls.hcell.compile();
56361 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56362 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56363 tpls.hsplit.disableFormats = true;
56365 tpls.hsplit.compile();
56368 tpls.body = new Roo.Template(
56369 '<table border="0" cellspacing="0" cellpadding="0">',
56370 "<tbody>{rows}</tbody>",
56373 tpls.body.disableFormats = true;
56375 tpls.body.compile();
56378 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56379 tpls.row.disableFormats = true;
56381 tpls.row.compile();
56384 tpls.cell = new Roo.Template(
56385 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56386 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56387 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56390 tpls.cell.disableFormats = true;
56392 tpls.cell.compile();
56394 this.templates = tpls;
56397 // remap these for backwards compat
56398 onColWidthChange : function(){
56399 this.updateColumns.apply(this, arguments);
56401 onHeaderChange : function(){
56402 this.updateHeaders.apply(this, arguments);
56404 onHiddenChange : function(){
56405 this.handleHiddenChange.apply(this, arguments);
56407 onColumnMove : function(){
56408 this.handleColumnMove.apply(this, arguments);
56410 onColumnLock : function(){
56411 this.handleLockChange.apply(this, arguments);
56414 onDataChange : function(){
56416 this.updateHeaderSortState();
56419 onClear : function(){
56423 onUpdate : function(ds, record){
56424 this.refreshRow(record);
56427 refreshRow : function(record){
56428 var ds = this.ds, index;
56429 if(typeof record == 'number'){
56431 record = ds.getAt(index);
56433 index = ds.indexOf(record);
56435 this.insertRows(ds, index, index, true);
56436 this.onRemove(ds, record, index+1, true);
56437 this.syncRowHeights(index, index);
56439 this.fireEvent("rowupdated", this, index, record);
56442 onAdd : function(ds, records, index){
56443 this.insertRows(ds, index, index + (records.length-1));
56446 onRemove : function(ds, record, index, isUpdate){
56447 if(isUpdate !== true){
56448 this.fireEvent("beforerowremoved", this, index, record);
56450 var bt = this.getBodyTable(), lt = this.getLockedTable();
56451 if(bt.rows[index]){
56452 bt.firstChild.removeChild(bt.rows[index]);
56454 if(lt.rows[index]){
56455 lt.firstChild.removeChild(lt.rows[index]);
56457 if(isUpdate !== true){
56458 this.stripeRows(index);
56459 this.syncRowHeights(index, index);
56461 this.fireEvent("rowremoved", this, index, record);
56465 onLoad : function(){
56466 this.scrollToTop();
56470 * Scrolls the grid to the top
56472 scrollToTop : function(){
56474 this.scroller.dom.scrollTop = 0;
56480 * Gets a panel in the header of the grid that can be used for toolbars etc.
56481 * After modifying the contents of this panel a call to grid.autoSize() may be
56482 * required to register any changes in size.
56483 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56484 * @return Roo.Element
56486 getHeaderPanel : function(doShow){
56488 this.headerPanel.show();
56490 return this.headerPanel;
56494 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56495 * After modifying the contents of this panel a call to grid.autoSize() may be
56496 * required to register any changes in size.
56497 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56498 * @return Roo.Element
56500 getFooterPanel : function(doShow){
56502 this.footerPanel.show();
56504 return this.footerPanel;
56507 initElements : function(){
56508 var E = Roo.Element;
56509 var el = this.grid.getGridEl().dom.firstChild;
56510 var cs = el.childNodes;
56512 this.el = new E(el);
56514 this.focusEl = new E(el.firstChild);
56515 this.focusEl.swallowEvent("click", true);
56517 this.headerPanel = new E(cs[1]);
56518 this.headerPanel.enableDisplayMode("block");
56520 this.scroller = new E(cs[2]);
56521 this.scrollSizer = new E(this.scroller.dom.firstChild);
56523 this.lockedWrap = new E(cs[3]);
56524 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56525 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56527 this.mainWrap = new E(cs[4]);
56528 this.mainHd = new E(this.mainWrap.dom.firstChild);
56529 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56531 this.footerPanel = new E(cs[5]);
56532 this.footerPanel.enableDisplayMode("block");
56534 this.resizeProxy = new E(cs[6]);
56536 this.headerSelector = String.format(
56537 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56538 this.lockedHd.id, this.mainHd.id
56541 this.splitterSelector = String.format(
56542 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56543 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56546 idToCssName : function(s)
56548 return s.replace(/[^a-z0-9]+/ig, '-');
56551 getHeaderCell : function(index){
56552 return Roo.DomQuery.select(this.headerSelector)[index];
56555 getHeaderCellMeasure : function(index){
56556 return this.getHeaderCell(index).firstChild;
56559 getHeaderCellText : function(index){
56560 return this.getHeaderCell(index).firstChild.firstChild;
56563 getLockedTable : function(){
56564 return this.lockedBody.dom.firstChild;
56567 getBodyTable : function(){
56568 return this.mainBody.dom.firstChild;
56571 getLockedRow : function(index){
56572 return this.getLockedTable().rows[index];
56575 getRow : function(index){
56576 return this.getBodyTable().rows[index];
56579 getRowComposite : function(index){
56581 this.rowEl = new Roo.CompositeElementLite();
56583 var els = [], lrow, mrow;
56584 if(lrow = this.getLockedRow(index)){
56587 if(mrow = this.getRow(index)){
56590 this.rowEl.elements = els;
56594 * Gets the 'td' of the cell
56596 * @param {Integer} rowIndex row to select
56597 * @param {Integer} colIndex column to select
56601 getCell : function(rowIndex, colIndex){
56602 var locked = this.cm.getLockedCount();
56604 if(colIndex < locked){
56605 source = this.lockedBody.dom.firstChild;
56607 source = this.mainBody.dom.firstChild;
56608 colIndex -= locked;
56610 return source.rows[rowIndex].childNodes[colIndex];
56613 getCellText : function(rowIndex, colIndex){
56614 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56617 getCellBox : function(cell){
56618 var b = this.fly(cell).getBox();
56619 if(Roo.isOpera){ // opera fails to report the Y
56620 b.y = cell.offsetTop + this.mainBody.getY();
56625 getCellIndex : function(cell){
56626 var id = String(cell.className).match(this.cellRE);
56628 return parseInt(id[1], 10);
56633 findHeaderIndex : function(n){
56634 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56635 return r ? this.getCellIndex(r) : false;
56638 findHeaderCell : function(n){
56639 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56640 return r ? r : false;
56643 findRowIndex : function(n){
56647 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56648 return r ? r.rowIndex : false;
56651 findCellIndex : function(node){
56652 var stop = this.el.dom;
56653 while(node && node != stop){
56654 if(this.findRE.test(node.className)){
56655 return this.getCellIndex(node);
56657 node = node.parentNode;
56662 getColumnId : function(index){
56663 return this.cm.getColumnId(index);
56666 getSplitters : function()
56668 if(this.splitterSelector){
56669 return Roo.DomQuery.select(this.splitterSelector);
56675 getSplitter : function(index){
56676 return this.getSplitters()[index];
56679 onRowOver : function(e, t){
56681 if((row = this.findRowIndex(t)) !== false){
56682 this.getRowComposite(row).addClass("x-grid-row-over");
56686 onRowOut : function(e, t){
56688 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56689 this.getRowComposite(row).removeClass("x-grid-row-over");
56693 renderHeaders : function(){
56695 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56696 var cb = [], lb = [], sb = [], lsb = [], p = {};
56697 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56698 p.cellId = "x-grid-hd-0-" + i;
56699 p.splitId = "x-grid-csplit-0-" + i;
56700 p.id = cm.getColumnId(i);
56701 p.value = cm.getColumnHeader(i) || "";
56702 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56703 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56704 if(!cm.isLocked(i)){
56705 cb[cb.length] = ct.apply(p);
56706 sb[sb.length] = st.apply(p);
56708 lb[lb.length] = ct.apply(p);
56709 lsb[lsb.length] = st.apply(p);
56712 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56713 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56716 updateHeaders : function(){
56717 var html = this.renderHeaders();
56718 this.lockedHd.update(html[0]);
56719 this.mainHd.update(html[1]);
56723 * Focuses the specified row.
56724 * @param {Number} row The row index
56726 focusRow : function(row)
56728 //Roo.log('GridView.focusRow');
56729 var x = this.scroller.dom.scrollLeft;
56730 this.focusCell(row, 0, false);
56731 this.scroller.dom.scrollLeft = x;
56735 * Focuses the specified cell.
56736 * @param {Number} row The row index
56737 * @param {Number} col The column index
56738 * @param {Boolean} hscroll false to disable horizontal scrolling
56740 focusCell : function(row, col, hscroll)
56742 //Roo.log('GridView.focusCell');
56743 var el = this.ensureVisible(row, col, hscroll);
56744 this.focusEl.alignTo(el, "tl-tl");
56746 this.focusEl.focus();
56748 this.focusEl.focus.defer(1, this.focusEl);
56753 * Scrolls the specified cell into view
56754 * @param {Number} row The row index
56755 * @param {Number} col The column index
56756 * @param {Boolean} hscroll false to disable horizontal scrolling
56758 ensureVisible : function(row, col, hscroll)
56760 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56761 //return null; //disable for testing.
56762 if(typeof row != "number"){
56763 row = row.rowIndex;
56765 if(row < 0 && row >= this.ds.getCount()){
56768 col = (col !== undefined ? col : 0);
56769 var cm = this.grid.colModel;
56770 while(cm.isHidden(col)){
56774 var el = this.getCell(row, col);
56778 var c = this.scroller.dom;
56780 var ctop = parseInt(el.offsetTop, 10);
56781 var cleft = parseInt(el.offsetLeft, 10);
56782 var cbot = ctop + el.offsetHeight;
56783 var cright = cleft + el.offsetWidth;
56785 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
56786 var stop = parseInt(c.scrollTop, 10);
56787 var sleft = parseInt(c.scrollLeft, 10);
56788 var sbot = stop + ch;
56789 var sright = sleft + c.clientWidth;
56791 Roo.log('GridView.ensureVisible:' +
56793 ' c.clientHeight:' + c.clientHeight +
56794 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
56802 c.scrollTop = ctop;
56803 //Roo.log("set scrolltop to ctop DISABLE?");
56804 }else if(cbot > sbot){
56805 //Roo.log("set scrolltop to cbot-ch");
56806 c.scrollTop = cbot-ch;
56809 if(hscroll !== false){
56811 c.scrollLeft = cleft;
56812 }else if(cright > sright){
56813 c.scrollLeft = cright-c.clientWidth;
56820 updateColumns : function(){
56821 this.grid.stopEditing();
56822 var cm = this.grid.colModel, colIds = this.getColumnIds();
56823 //var totalWidth = cm.getTotalWidth();
56825 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56826 //if(cm.isHidden(i)) continue;
56827 var w = cm.getColumnWidth(i);
56828 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56829 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56831 this.updateSplitters();
56834 generateRules : function(cm){
56835 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
56836 Roo.util.CSS.removeStyleSheet(rulesId);
56837 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56838 var cid = cm.getColumnId(i);
56840 if(cm.config[i].align){
56841 align = 'text-align:'+cm.config[i].align+';';
56844 if(cm.isHidden(i)){
56845 hidden = 'display:none;';
56847 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
56849 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
56850 this.hdSelector, cid, " {\n", align, width, "}\n",
56851 this.tdSelector, cid, " {\n",hidden,"\n}\n",
56852 this.splitSelector, cid, " {\n", hidden , "\n}\n");
56854 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56857 updateSplitters : function(){
56858 var cm = this.cm, s = this.getSplitters();
56859 if(s){ // splitters not created yet
56860 var pos = 0, locked = true;
56861 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56862 if(cm.isHidden(i)) {
56865 var w = cm.getColumnWidth(i); // make sure it's a number
56866 if(!cm.isLocked(i) && locked){
56871 s[i].style.left = (pos-this.splitOffset) + "px";
56876 handleHiddenChange : function(colModel, colIndex, hidden){
56878 this.hideColumn(colIndex);
56880 this.unhideColumn(colIndex);
56884 hideColumn : function(colIndex){
56885 var cid = this.getColumnId(colIndex);
56886 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
56887 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
56889 this.updateHeaders();
56891 this.updateSplitters();
56895 unhideColumn : function(colIndex){
56896 var cid = this.getColumnId(colIndex);
56897 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
56898 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
56901 this.updateHeaders();
56903 this.updateSplitters();
56907 insertRows : function(dm, firstRow, lastRow, isUpdate){
56908 if(firstRow == 0 && lastRow == dm.getCount()-1){
56912 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
56914 var s = this.getScrollState();
56915 var markup = this.renderRows(firstRow, lastRow);
56916 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
56917 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
56918 this.restoreScroll(s);
56920 this.fireEvent("rowsinserted", this, firstRow, lastRow);
56921 this.syncRowHeights(firstRow, lastRow);
56922 this.stripeRows(firstRow);
56928 bufferRows : function(markup, target, index){
56929 var before = null, trows = target.rows, tbody = target.tBodies[0];
56930 if(index < trows.length){
56931 before = trows[index];
56933 var b = document.createElement("div");
56934 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
56935 var rows = b.firstChild.rows;
56936 for(var i = 0, len = rows.length; i < len; i++){
56938 tbody.insertBefore(rows[0], before);
56940 tbody.appendChild(rows[0]);
56947 deleteRows : function(dm, firstRow, lastRow){
56948 if(dm.getRowCount()<1){
56949 this.fireEvent("beforerefresh", this);
56950 this.mainBody.update("");
56951 this.lockedBody.update("");
56952 this.fireEvent("refresh", this);
56954 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
56955 var bt = this.getBodyTable();
56956 var tbody = bt.firstChild;
56957 var rows = bt.rows;
56958 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
56959 tbody.removeChild(rows[firstRow]);
56961 this.stripeRows(firstRow);
56962 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
56966 updateRows : function(dataSource, firstRow, lastRow){
56967 var s = this.getScrollState();
56969 this.restoreScroll(s);
56972 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
56976 this.updateHeaderSortState();
56979 getScrollState : function(){
56981 var sb = this.scroller.dom;
56982 return {left: sb.scrollLeft, top: sb.scrollTop};
56985 stripeRows : function(startRow){
56986 if(!this.grid.stripeRows || this.ds.getCount() < 1){
56989 startRow = startRow || 0;
56990 var rows = this.getBodyTable().rows;
56991 var lrows = this.getLockedTable().rows;
56992 var cls = ' x-grid-row-alt ';
56993 for(var i = startRow, len = rows.length; i < len; i++){
56994 var row = rows[i], lrow = lrows[i];
56995 var isAlt = ((i+1) % 2 == 0);
56996 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
56997 if(isAlt == hasAlt){
57001 row.className += " x-grid-row-alt";
57003 row.className = row.className.replace("x-grid-row-alt", "");
57006 lrow.className = row.className;
57011 restoreScroll : function(state){
57012 //Roo.log('GridView.restoreScroll');
57013 var sb = this.scroller.dom;
57014 sb.scrollLeft = state.left;
57015 sb.scrollTop = state.top;
57019 syncScroll : function(){
57020 //Roo.log('GridView.syncScroll');
57021 var sb = this.scroller.dom;
57022 var sh = this.mainHd.dom;
57023 var bs = this.mainBody.dom;
57024 var lv = this.lockedBody.dom;
57025 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
57026 lv.scrollTop = bs.scrollTop = sb.scrollTop;
57029 handleScroll : function(e){
57031 var sb = this.scroller.dom;
57032 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
57036 handleWheel : function(e){
57037 var d = e.getWheelDelta();
57038 this.scroller.dom.scrollTop -= d*22;
57039 // set this here to prevent jumpy scrolling on large tables
57040 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
57044 renderRows : function(startRow, endRow){
57045 // pull in all the crap needed to render rows
57046 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
57047 var colCount = cm.getColumnCount();
57049 if(ds.getCount() < 1){
57053 // build a map for all the columns
57055 for(var i = 0; i < colCount; i++){
57056 var name = cm.getDataIndex(i);
57058 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57059 renderer : cm.getRenderer(i),
57060 id : cm.getColumnId(i),
57061 locked : cm.isLocked(i),
57062 has_editor : cm.isCellEditable(i)
57066 startRow = startRow || 0;
57067 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57069 // records to render
57070 var rs = ds.getRange(startRow, endRow);
57072 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57075 // As much as I hate to duplicate code, this was branched because FireFox really hates
57076 // [].join("") on strings. The performance difference was substantial enough to
57077 // branch this function
57078 doRender : Roo.isGecko ?
57079 function(cs, rs, ds, startRow, colCount, stripe){
57080 var ts = this.templates, ct = ts.cell, rt = ts.row;
57082 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57084 var hasListener = this.grid.hasListener('rowclass');
57086 for(var j = 0, len = rs.length; j < len; j++){
57087 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57088 for(var i = 0; i < colCount; i++){
57090 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57092 p.css = p.attr = "";
57093 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57094 if(p.value == undefined || p.value === "") {
57095 p.value = " ";
57098 p.css += ' x-grid-editable-cell';
57100 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57101 p.css += ' x-grid-dirty-cell';
57103 var markup = ct.apply(p);
57111 if(stripe && ((rowIndex+1) % 2 == 0)){
57112 alt.push("x-grid-row-alt")
57115 alt.push( " x-grid-dirty-row");
57118 if(this.getRowClass){
57119 alt.push(this.getRowClass(r, rowIndex));
57125 rowIndex : rowIndex,
57128 this.grid.fireEvent('rowclass', this, rowcfg);
57129 alt.push(rowcfg.rowClass);
57131 rp.alt = alt.join(" ");
57132 lbuf+= rt.apply(rp);
57134 buf+= rt.apply(rp);
57136 return [lbuf, buf];
57138 function(cs, rs, ds, startRow, colCount, stripe){
57139 var ts = this.templates, ct = ts.cell, rt = ts.row;
57141 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57142 var hasListener = this.grid.hasListener('rowclass');
57145 for(var j = 0, len = rs.length; j < len; j++){
57146 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57147 for(var i = 0; i < colCount; i++){
57149 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57151 p.css = p.attr = "";
57152 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57153 if(p.value == undefined || p.value === "") {
57154 p.value = " ";
57158 p.css += ' x-grid-editable-cell';
57160 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57161 p.css += ' x-grid-dirty-cell'
57164 var markup = ct.apply(p);
57166 cb[cb.length] = markup;
57168 lcb[lcb.length] = markup;
57172 if(stripe && ((rowIndex+1) % 2 == 0)){
57173 alt.push( "x-grid-row-alt");
57176 alt.push(" x-grid-dirty-row");
57179 if(this.getRowClass){
57180 alt.push( this.getRowClass(r, rowIndex));
57186 rowIndex : rowIndex,
57189 this.grid.fireEvent('rowclass', this, rowcfg);
57190 alt.push(rowcfg.rowClass);
57193 rp.alt = alt.join(" ");
57194 rp.cells = lcb.join("");
57195 lbuf[lbuf.length] = rt.apply(rp);
57196 rp.cells = cb.join("");
57197 buf[buf.length] = rt.apply(rp);
57199 return [lbuf.join(""), buf.join("")];
57202 renderBody : function(){
57203 var markup = this.renderRows();
57204 var bt = this.templates.body;
57205 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57209 * Refreshes the grid
57210 * @param {Boolean} headersToo
57212 refresh : function(headersToo){
57213 this.fireEvent("beforerefresh", this);
57214 this.grid.stopEditing();
57215 var result = this.renderBody();
57216 this.lockedBody.update(result[0]);
57217 this.mainBody.update(result[1]);
57218 if(headersToo === true){
57219 this.updateHeaders();
57220 this.updateColumns();
57221 this.updateSplitters();
57222 this.updateHeaderSortState();
57224 this.syncRowHeights();
57226 this.fireEvent("refresh", this);
57229 handleColumnMove : function(cm, oldIndex, newIndex){
57230 this.indexMap = null;
57231 var s = this.getScrollState();
57232 this.refresh(true);
57233 this.restoreScroll(s);
57234 this.afterMove(newIndex);
57237 afterMove : function(colIndex){
57238 if(this.enableMoveAnim && Roo.enableFx){
57239 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57241 // if multisort - fix sortOrder, and reload..
57242 if (this.grid.dataSource.multiSort) {
57243 // the we can call sort again..
57244 var dm = this.grid.dataSource;
57245 var cm = this.grid.colModel;
57247 for(var i = 0; i < cm.config.length; i++ ) {
57249 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57250 continue; // dont' bother, it's not in sort list or being set.
57253 so.push(cm.config[i].dataIndex);
57256 dm.load(dm.lastOptions);
57263 updateCell : function(dm, rowIndex, dataIndex){
57264 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57265 if(typeof colIndex == "undefined"){ // not present in grid
57268 var cm = this.grid.colModel;
57269 var cell = this.getCell(rowIndex, colIndex);
57270 var cellText = this.getCellText(rowIndex, colIndex);
57273 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57274 id : cm.getColumnId(colIndex),
57275 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57277 var renderer = cm.getRenderer(colIndex);
57278 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57279 if(typeof val == "undefined" || val === "") {
57282 cellText.innerHTML = val;
57283 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57284 this.syncRowHeights(rowIndex, rowIndex);
57287 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57289 if(this.grid.autoSizeHeaders){
57290 var h = this.getHeaderCellMeasure(colIndex);
57291 maxWidth = Math.max(maxWidth, h.scrollWidth);
57294 if(this.cm.isLocked(colIndex)){
57295 tb = this.getLockedTable();
57298 tb = this.getBodyTable();
57299 index = colIndex - this.cm.getLockedCount();
57302 var rows = tb.rows;
57303 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57304 for(var i = 0; i < stopIndex; i++){
57305 var cell = rows[i].childNodes[index].firstChild;
57306 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57309 return maxWidth + /*margin for error in IE*/ 5;
57312 * Autofit a column to its content.
57313 * @param {Number} colIndex
57314 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57316 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57317 if(this.cm.isHidden(colIndex)){
57318 return; // can't calc a hidden column
57321 var cid = this.cm.getColumnId(colIndex);
57322 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57323 if(this.grid.autoSizeHeaders){
57324 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57327 var newWidth = this.calcColumnWidth(colIndex);
57328 this.cm.setColumnWidth(colIndex,
57329 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57330 if(!suppressEvent){
57331 this.grid.fireEvent("columnresize", colIndex, newWidth);
57336 * Autofits all columns to their content and then expands to fit any extra space in the grid
57338 autoSizeColumns : function(){
57339 var cm = this.grid.colModel;
57340 var colCount = cm.getColumnCount();
57341 for(var i = 0; i < colCount; i++){
57342 this.autoSizeColumn(i, true, true);
57344 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57347 this.updateColumns();
57353 * Autofits all columns to the grid's width proportionate with their current size
57354 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57356 fitColumns : function(reserveScrollSpace){
57357 var cm = this.grid.colModel;
57358 var colCount = cm.getColumnCount();
57362 for (i = 0; i < colCount; i++){
57363 if(!cm.isHidden(i) && !cm.isFixed(i)){
57364 w = cm.getColumnWidth(i);
57370 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57371 if(reserveScrollSpace){
57374 var frac = (avail - cm.getTotalWidth())/width;
57375 while (cols.length){
57378 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57380 this.updateColumns();
57384 onRowSelect : function(rowIndex){
57385 var row = this.getRowComposite(rowIndex);
57386 row.addClass("x-grid-row-selected");
57389 onRowDeselect : function(rowIndex){
57390 var row = this.getRowComposite(rowIndex);
57391 row.removeClass("x-grid-row-selected");
57394 onCellSelect : function(row, col){
57395 var cell = this.getCell(row, col);
57397 Roo.fly(cell).addClass("x-grid-cell-selected");
57401 onCellDeselect : function(row, col){
57402 var cell = this.getCell(row, col);
57404 Roo.fly(cell).removeClass("x-grid-cell-selected");
57408 updateHeaderSortState : function(){
57410 // sort state can be single { field: xxx, direction : yyy}
57411 // or { xxx=>ASC , yyy : DESC ..... }
57414 if (!this.ds.multiSort) {
57415 var state = this.ds.getSortState();
57419 mstate[state.field] = state.direction;
57420 // FIXME... - this is not used here.. but might be elsewhere..
57421 this.sortState = state;
57424 mstate = this.ds.sortToggle;
57426 //remove existing sort classes..
57428 var sc = this.sortClasses;
57429 var hds = this.el.select(this.headerSelector).removeClass(sc);
57431 for(var f in mstate) {
57433 var sortColumn = this.cm.findColumnIndex(f);
57435 if(sortColumn != -1){
57436 var sortDir = mstate[f];
57437 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57446 handleHeaderClick : function(g, index,e){
57448 Roo.log("header click");
57451 // touch events on header are handled by context
57452 this.handleHdCtx(g,index,e);
57457 if(this.headersDisabled){
57460 var dm = g.dataSource, cm = g.colModel;
57461 if(!cm.isSortable(index)){
57466 if (dm.multiSort) {
57467 // update the sortOrder
57469 for(var i = 0; i < cm.config.length; i++ ) {
57471 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57472 continue; // dont' bother, it's not in sort list or being set.
57475 so.push(cm.config[i].dataIndex);
57481 dm.sort(cm.getDataIndex(index));
57485 destroy : function(){
57487 this.colMenu.removeAll();
57488 Roo.menu.MenuMgr.unregister(this.colMenu);
57489 this.colMenu.getEl().remove();
57490 delete this.colMenu;
57493 this.hmenu.removeAll();
57494 Roo.menu.MenuMgr.unregister(this.hmenu);
57495 this.hmenu.getEl().remove();
57498 if(this.grid.enableColumnMove){
57499 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57501 for(var dd in dds){
57502 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57503 var elid = dds[dd].dragElId;
57505 Roo.get(elid).remove();
57506 } else if(dds[dd].config.isTarget){
57507 dds[dd].proxyTop.remove();
57508 dds[dd].proxyBottom.remove();
57511 if(Roo.dd.DDM.locationCache[dd]){
57512 delete Roo.dd.DDM.locationCache[dd];
57515 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57518 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57519 this.bind(null, null);
57520 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57523 handleLockChange : function(){
57524 this.refresh(true);
57527 onDenyColumnLock : function(){
57531 onDenyColumnHide : function(){
57535 handleHdMenuClick : function(item){
57536 var index = this.hdCtxIndex;
57537 var cm = this.cm, ds = this.ds;
57540 ds.sort(cm.getDataIndex(index), "ASC");
57543 ds.sort(cm.getDataIndex(index), "DESC");
57546 var lc = cm.getLockedCount();
57547 if(cm.getColumnCount(true) <= lc+1){
57548 this.onDenyColumnLock();
57552 cm.setLocked(index, true, true);
57553 cm.moveColumn(index, lc);
57554 this.grid.fireEvent("columnmove", index, lc);
57556 cm.setLocked(index, true);
57560 var lc = cm.getLockedCount();
57561 if((lc-1) != index){
57562 cm.setLocked(index, false, true);
57563 cm.moveColumn(index, lc-1);
57564 this.grid.fireEvent("columnmove", index, lc-1);
57566 cm.setLocked(index, false);
57569 case 'wider': // used to expand cols on touch..
57571 var cw = cm.getColumnWidth(index);
57572 cw += (item.id == 'wider' ? 1 : -1) * 50;
57573 cw = Math.max(0, cw);
57574 cw = Math.min(cw,4000);
57575 cm.setColumnWidth(index, cw);
57579 index = cm.getIndexById(item.id.substr(4));
57581 if(item.checked && cm.getColumnCount(true) <= 1){
57582 this.onDenyColumnHide();
57585 cm.setHidden(index, item.checked);
57591 beforeColMenuShow : function(){
57592 var cm = this.cm, colCount = cm.getColumnCount();
57593 this.colMenu.removeAll();
57594 for(var i = 0; i < colCount; i++){
57595 this.colMenu.add(new Roo.menu.CheckItem({
57596 id: "col-"+cm.getColumnId(i),
57597 text: cm.getColumnHeader(i),
57598 checked: !cm.isHidden(i),
57604 handleHdCtx : function(g, index, e){
57606 var hd = this.getHeaderCell(index);
57607 this.hdCtxIndex = index;
57608 var ms = this.hmenu.items, cm = this.cm;
57609 ms.get("asc").setDisabled(!cm.isSortable(index));
57610 ms.get("desc").setDisabled(!cm.isSortable(index));
57611 if(this.grid.enableColLock !== false){
57612 ms.get("lock").setDisabled(cm.isLocked(index));
57613 ms.get("unlock").setDisabled(!cm.isLocked(index));
57615 this.hmenu.show(hd, "tl-bl");
57618 handleHdOver : function(e){
57619 var hd = this.findHeaderCell(e.getTarget());
57620 if(hd && !this.headersDisabled){
57621 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57622 this.fly(hd).addClass("x-grid-hd-over");
57627 handleHdOut : function(e){
57628 var hd = this.findHeaderCell(e.getTarget());
57630 this.fly(hd).removeClass("x-grid-hd-over");
57634 handleSplitDblClick : function(e, t){
57635 var i = this.getCellIndex(t);
57636 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57637 this.autoSizeColumn(i, true);
57642 render : function(){
57645 var colCount = cm.getColumnCount();
57647 if(this.grid.monitorWindowResize === true){
57648 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57650 var header = this.renderHeaders();
57651 var body = this.templates.body.apply({rows:""});
57652 var html = this.templates.master.apply({
57655 lockedHeader: header[0],
57659 //this.updateColumns();
57661 this.grid.getGridEl().dom.innerHTML = html;
57663 this.initElements();
57665 // a kludge to fix the random scolling effect in webkit
57666 this.el.on("scroll", function() {
57667 this.el.dom.scrollTop=0; // hopefully not recursive..
57670 this.scroller.on("scroll", this.handleScroll, this);
57671 this.lockedBody.on("mousewheel", this.handleWheel, this);
57672 this.mainBody.on("mousewheel", this.handleWheel, this);
57674 this.mainHd.on("mouseover", this.handleHdOver, this);
57675 this.mainHd.on("mouseout", this.handleHdOut, this);
57676 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57677 {delegate: "."+this.splitClass});
57679 this.lockedHd.on("mouseover", this.handleHdOver, this);
57680 this.lockedHd.on("mouseout", this.handleHdOut, this);
57681 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57682 {delegate: "."+this.splitClass});
57684 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57685 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57688 this.updateSplitters();
57690 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57691 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57692 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57695 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57696 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57698 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57699 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57701 if(this.grid.enableColLock !== false){
57702 this.hmenu.add('-',
57703 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57704 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57708 this.hmenu.add('-',
57709 {id:"wider", text: this.columnsWiderText},
57710 {id:"narrow", text: this.columnsNarrowText }
57716 if(this.grid.enableColumnHide !== false){
57718 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57719 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57720 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57722 this.hmenu.add('-',
57723 {id:"columns", text: this.columnsText, menu: this.colMenu}
57726 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57728 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57731 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57732 this.dd = new Roo.grid.GridDragZone(this.grid, {
57733 ddGroup : this.grid.ddGroup || 'GridDD'
57739 for(var i = 0; i < colCount; i++){
57740 if(cm.isHidden(i)){
57741 this.hideColumn(i);
57743 if(cm.config[i].align){
57744 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57745 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57749 this.updateHeaderSortState();
57751 this.beforeInitialResize();
57754 // two part rendering gives faster view to the user
57755 this.renderPhase2.defer(1, this);
57758 renderPhase2 : function(){
57759 // render the rows now
57761 if(this.grid.autoSizeColumns){
57762 this.autoSizeColumns();
57766 beforeInitialResize : function(){
57770 onColumnSplitterMoved : function(i, w){
57771 this.userResized = true;
57772 var cm = this.grid.colModel;
57773 cm.setColumnWidth(i, w, true);
57774 var cid = cm.getColumnId(i);
57775 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57776 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57777 this.updateSplitters();
57779 this.grid.fireEvent("columnresize", i, w);
57782 syncRowHeights : function(startIndex, endIndex){
57783 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
57784 startIndex = startIndex || 0;
57785 var mrows = this.getBodyTable().rows;
57786 var lrows = this.getLockedTable().rows;
57787 var len = mrows.length-1;
57788 endIndex = Math.min(endIndex || len, len);
57789 for(var i = startIndex; i <= endIndex; i++){
57790 var m = mrows[i], l = lrows[i];
57791 var h = Math.max(m.offsetHeight, l.offsetHeight);
57792 m.style.height = l.style.height = h + "px";
57797 layout : function(initialRender, is2ndPass)
57800 var auto = g.autoHeight;
57801 var scrollOffset = 16;
57802 var c = g.getGridEl(), cm = this.cm,
57803 expandCol = g.autoExpandColumn,
57805 //c.beginMeasure();
57807 if(!c.dom.offsetWidth){ // display:none?
57809 this.lockedWrap.show();
57810 this.mainWrap.show();
57815 var hasLock = this.cm.isLocked(0);
57817 var tbh = this.headerPanel.getHeight();
57818 var bbh = this.footerPanel.getHeight();
57821 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
57822 var newHeight = ch + c.getBorderWidth("tb");
57824 newHeight = Math.min(g.maxHeight, newHeight);
57826 c.setHeight(newHeight);
57830 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
57833 var s = this.scroller;
57835 var csize = c.getSize(true);
57837 this.el.setSize(csize.width, csize.height);
57839 this.headerPanel.setWidth(csize.width);
57840 this.footerPanel.setWidth(csize.width);
57842 var hdHeight = this.mainHd.getHeight();
57843 var vw = csize.width;
57844 var vh = csize.height - (tbh + bbh);
57848 var bt = this.getBodyTable();
57850 if(cm.getLockedCount() == cm.config.length){
57851 bt = this.getLockedTable();
57854 var ltWidth = hasLock ?
57855 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
57857 var scrollHeight = bt.offsetHeight;
57858 var scrollWidth = ltWidth + bt.offsetWidth;
57859 var vscroll = false, hscroll = false;
57861 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
57863 var lw = this.lockedWrap, mw = this.mainWrap;
57864 var lb = this.lockedBody, mb = this.mainBody;
57866 setTimeout(function(){
57867 var t = s.dom.offsetTop;
57868 var w = s.dom.clientWidth,
57869 h = s.dom.clientHeight;
57872 lw.setSize(ltWidth, h);
57874 mw.setLeftTop(ltWidth, t);
57875 mw.setSize(w-ltWidth, h);
57877 lb.setHeight(h-hdHeight);
57878 mb.setHeight(h-hdHeight);
57880 if(is2ndPass !== true && !gv.userResized && expandCol){
57881 // high speed resize without full column calculation
57883 var ci = cm.getIndexById(expandCol);
57885 ci = cm.findColumnIndex(expandCol);
57887 ci = Math.max(0, ci); // make sure it's got at least the first col.
57888 var expandId = cm.getColumnId(ci);
57889 var tw = cm.getTotalWidth(false);
57890 var currentWidth = cm.getColumnWidth(ci);
57891 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
57892 if(currentWidth != cw){
57893 cm.setColumnWidth(ci, cw, true);
57894 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57895 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57896 gv.updateSplitters();
57897 gv.layout(false, true);
57909 onWindowResize : function(){
57910 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
57916 appendFooter : function(parentEl){
57920 sortAscText : "Sort Ascending",
57921 sortDescText : "Sort Descending",
57922 lockText : "Lock Column",
57923 unlockText : "Unlock Column",
57924 columnsText : "Columns",
57926 columnsWiderText : "Wider",
57927 columnsNarrowText : "Thinner"
57931 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
57932 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
57933 this.proxy.el.addClass('x-grid3-col-dd');
57936 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
57937 handleMouseDown : function(e){
57941 callHandleMouseDown : function(e){
57942 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
57947 * Ext JS Library 1.1.1
57948 * Copyright(c) 2006-2007, Ext JS, LLC.
57950 * Originally Released Under LGPL - original licence link has changed is not relivant.
57953 * <script type="text/javascript">
57957 // This is a support class used internally by the Grid components
57958 Roo.grid.SplitDragZone = function(grid, hd, hd2){
57960 this.view = grid.getView();
57961 this.proxy = this.view.resizeProxy;
57962 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
57963 "gridSplitters" + this.grid.getGridEl().id, {
57964 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
57966 this.setHandleElId(Roo.id(hd));
57967 this.setOuterHandleElId(Roo.id(hd2));
57968 this.scroll = false;
57970 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
57971 fly: Roo.Element.fly,
57973 b4StartDrag : function(x, y){
57974 this.view.headersDisabled = true;
57975 this.proxy.setHeight(this.view.mainWrap.getHeight());
57976 var w = this.cm.getColumnWidth(this.cellIndex);
57977 var minw = Math.max(w-this.grid.minColumnWidth, 0);
57978 this.resetConstraints();
57979 this.setXConstraint(minw, 1000);
57980 this.setYConstraint(0, 0);
57981 this.minX = x - minw;
57982 this.maxX = x + 1000;
57984 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
57988 handleMouseDown : function(e){
57989 ev = Roo.EventObject.setEvent(e);
57990 var t = this.fly(ev.getTarget());
57991 if(t.hasClass("x-grid-split")){
57992 this.cellIndex = this.view.getCellIndex(t.dom);
57993 this.split = t.dom;
57994 this.cm = this.grid.colModel;
57995 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
57996 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
58001 endDrag : function(e){
58002 this.view.headersDisabled = false;
58003 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
58004 var diff = endX - this.startPos;
58005 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
58008 autoOffset : function(){
58009 this.setDelta(0,0);
58013 * Ext JS Library 1.1.1
58014 * Copyright(c) 2006-2007, Ext JS, LLC.
58016 * Originally Released Under LGPL - original licence link has changed is not relivant.
58019 * <script type="text/javascript">
58023 // This is a support class used internally by the Grid components
58024 Roo.grid.GridDragZone = function(grid, config){
58025 this.view = grid.getView();
58026 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
58027 if(this.view.lockedBody){
58028 this.setHandleElId(Roo.id(this.view.mainBody.dom));
58029 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
58031 this.scroll = false;
58033 this.ddel = document.createElement('div');
58034 this.ddel.className = 'x-grid-dd-wrap';
58037 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
58038 ddGroup : "GridDD",
58040 getDragData : function(e){
58041 var t = Roo.lib.Event.getTarget(e);
58042 var rowIndex = this.view.findRowIndex(t);
58043 var sm = this.grid.selModel;
58045 //Roo.log(rowIndex);
58047 if (sm.getSelectedCell) {
58048 // cell selection..
58049 if (!sm.getSelectedCell()) {
58052 if (rowIndex != sm.getSelectedCell()[0]) {
58057 if (sm.getSelections && sm.getSelections().length < 1) {
58062 // before it used to all dragging of unseleted... - now we dont do that.
58063 if(rowIndex !== false){
58068 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58070 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58073 if (e.hasModifier()){
58074 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58077 Roo.log("getDragData");
58082 rowIndex: rowIndex,
58083 selections: sm.getSelections ? sm.getSelections() : (
58084 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
58091 onInitDrag : function(e){
58092 var data = this.dragData;
58093 this.ddel.innerHTML = this.grid.getDragDropText();
58094 this.proxy.update(this.ddel);
58095 // fire start drag?
58098 afterRepair : function(){
58099 this.dragging = false;
58102 getRepairXY : function(e, data){
58106 onEndDrag : function(data, e){
58110 onValidDrop : function(dd, e, id){
58115 beforeInvalidDrop : function(e, id){
58120 * Ext JS Library 1.1.1
58121 * Copyright(c) 2006-2007, Ext JS, LLC.
58123 * Originally Released Under LGPL - original licence link has changed is not relivant.
58126 * <script type="text/javascript">
58131 * @class Roo.grid.ColumnModel
58132 * @extends Roo.util.Observable
58133 * This is the default implementation of a ColumnModel used by the Grid. It defines
58134 * the columns in the grid.
58137 var colModel = new Roo.grid.ColumnModel([
58138 {header: "Ticker", width: 60, sortable: true, locked: true},
58139 {header: "Company Name", width: 150, sortable: true},
58140 {header: "Market Cap.", width: 100, sortable: true},
58141 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58142 {header: "Employees", width: 100, sortable: true, resizable: false}
58147 * The config options listed for this class are options which may appear in each
58148 * individual column definition.
58149 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58151 * @param {Object} config An Array of column config objects. See this class's
58152 * config objects for details.
58154 Roo.grid.ColumnModel = function(config){
58156 * The config passed into the constructor
58158 this.config = config;
58161 // if no id, create one
58162 // if the column does not have a dataIndex mapping,
58163 // map it to the order it is in the config
58164 for(var i = 0, len = config.length; i < len; i++){
58166 if(typeof c.dataIndex == "undefined"){
58169 if(typeof c.renderer == "string"){
58170 c.renderer = Roo.util.Format[c.renderer];
58172 if(typeof c.id == "undefined"){
58175 if(c.editor && c.editor.xtype){
58176 c.editor = Roo.factory(c.editor, Roo.grid);
58178 if(c.editor && c.editor.isFormField){
58179 c.editor = new Roo.grid.GridEditor(c.editor);
58181 this.lookup[c.id] = c;
58185 * The width of columns which have no width specified (defaults to 100)
58188 this.defaultWidth = 100;
58191 * Default sortable of columns which have no sortable specified (defaults to false)
58194 this.defaultSortable = false;
58198 * @event widthchange
58199 * Fires when the width of a column changes.
58200 * @param {ColumnModel} this
58201 * @param {Number} columnIndex The column index
58202 * @param {Number} newWidth The new width
58204 "widthchange": true,
58206 * @event headerchange
58207 * Fires when the text of a header changes.
58208 * @param {ColumnModel} this
58209 * @param {Number} columnIndex The column index
58210 * @param {Number} newText The new header text
58212 "headerchange": true,
58214 * @event hiddenchange
58215 * Fires when a column is hidden or "unhidden".
58216 * @param {ColumnModel} this
58217 * @param {Number} columnIndex The column index
58218 * @param {Boolean} hidden true if hidden, false otherwise
58220 "hiddenchange": true,
58222 * @event columnmoved
58223 * Fires when a column is moved.
58224 * @param {ColumnModel} this
58225 * @param {Number} oldIndex
58226 * @param {Number} newIndex
58228 "columnmoved" : true,
58230 * @event columlockchange
58231 * Fires when a column's locked state is changed
58232 * @param {ColumnModel} this
58233 * @param {Number} colIndex
58234 * @param {Boolean} locked true if locked
58236 "columnlockchange" : true
58238 Roo.grid.ColumnModel.superclass.constructor.call(this);
58240 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58242 * @cfg {String} header The header text to display in the Grid view.
58245 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58246 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58247 * specified, the column's index is used as an index into the Record's data Array.
58250 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58251 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58254 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58255 * Defaults to the value of the {@link #defaultSortable} property.
58256 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58259 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58262 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58265 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58268 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58271 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58272 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58273 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58274 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58277 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58280 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58283 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58286 * @cfg {String} cursor (Optional)
58289 * @cfg {String} tooltip (Optional)
58292 * @cfg {Number} xs (Optional)
58295 * @cfg {Number} sm (Optional)
58298 * @cfg {Number} md (Optional)
58301 * @cfg {Number} lg (Optional)
58304 * Returns the id of the column at the specified index.
58305 * @param {Number} index The column index
58306 * @return {String} the id
58308 getColumnId : function(index){
58309 return this.config[index].id;
58313 * Returns the column for a specified id.
58314 * @param {String} id The column id
58315 * @return {Object} the column
58317 getColumnById : function(id){
58318 return this.lookup[id];
58323 * Returns the column for a specified dataIndex.
58324 * @param {String} dataIndex The column dataIndex
58325 * @return {Object|Boolean} the column or false if not found
58327 getColumnByDataIndex: function(dataIndex){
58328 var index = this.findColumnIndex(dataIndex);
58329 return index > -1 ? this.config[index] : false;
58333 * Returns the index for a specified column id.
58334 * @param {String} id The column id
58335 * @return {Number} the index, or -1 if not found
58337 getIndexById : function(id){
58338 for(var i = 0, len = this.config.length; i < len; i++){
58339 if(this.config[i].id == id){
58347 * Returns the index for a specified column dataIndex.
58348 * @param {String} dataIndex The column dataIndex
58349 * @return {Number} the index, or -1 if not found
58352 findColumnIndex : function(dataIndex){
58353 for(var i = 0, len = this.config.length; i < len; i++){
58354 if(this.config[i].dataIndex == dataIndex){
58362 moveColumn : function(oldIndex, newIndex){
58363 var c = this.config[oldIndex];
58364 this.config.splice(oldIndex, 1);
58365 this.config.splice(newIndex, 0, c);
58366 this.dataMap = null;
58367 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58370 isLocked : function(colIndex){
58371 return this.config[colIndex].locked === true;
58374 setLocked : function(colIndex, value, suppressEvent){
58375 if(this.isLocked(colIndex) == value){
58378 this.config[colIndex].locked = value;
58379 if(!suppressEvent){
58380 this.fireEvent("columnlockchange", this, colIndex, value);
58384 getTotalLockedWidth : function(){
58385 var totalWidth = 0;
58386 for(var i = 0; i < this.config.length; i++){
58387 if(this.isLocked(i) && !this.isHidden(i)){
58388 this.totalWidth += this.getColumnWidth(i);
58394 getLockedCount : function(){
58395 for(var i = 0, len = this.config.length; i < len; i++){
58396 if(!this.isLocked(i)){
58401 return this.config.length;
58405 * Returns the number of columns.
58408 getColumnCount : function(visibleOnly){
58409 if(visibleOnly === true){
58411 for(var i = 0, len = this.config.length; i < len; i++){
58412 if(!this.isHidden(i)){
58418 return this.config.length;
58422 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58423 * @param {Function} fn
58424 * @param {Object} scope (optional)
58425 * @return {Array} result
58427 getColumnsBy : function(fn, scope){
58429 for(var i = 0, len = this.config.length; i < len; i++){
58430 var c = this.config[i];
58431 if(fn.call(scope||this, c, i) === true){
58439 * Returns true if the specified column is sortable.
58440 * @param {Number} col The column index
58441 * @return {Boolean}
58443 isSortable : function(col){
58444 if(typeof this.config[col].sortable == "undefined"){
58445 return this.defaultSortable;
58447 return this.config[col].sortable;
58451 * Returns the rendering (formatting) function defined for the column.
58452 * @param {Number} col The column index.
58453 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58455 getRenderer : function(col){
58456 if(!this.config[col].renderer){
58457 return Roo.grid.ColumnModel.defaultRenderer;
58459 return this.config[col].renderer;
58463 * Sets the rendering (formatting) function for a column.
58464 * @param {Number} col The column index
58465 * @param {Function} fn The function to use to process the cell's raw data
58466 * to return HTML markup for the grid view. The render function is called with
58467 * the following parameters:<ul>
58468 * <li>Data value.</li>
58469 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58470 * <li>css A CSS style string to apply to the table cell.</li>
58471 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58472 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58473 * <li>Row index</li>
58474 * <li>Column index</li>
58475 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58477 setRenderer : function(col, fn){
58478 this.config[col].renderer = fn;
58482 * Returns the width for the specified column.
58483 * @param {Number} col The column index
58486 getColumnWidth : function(col){
58487 return this.config[col].width * 1 || this.defaultWidth;
58491 * Sets the width for a column.
58492 * @param {Number} col The column index
58493 * @param {Number} width The new width
58495 setColumnWidth : function(col, width, suppressEvent){
58496 this.config[col].width = width;
58497 this.totalWidth = null;
58498 if(!suppressEvent){
58499 this.fireEvent("widthchange", this, col, width);
58504 * Returns the total width of all columns.
58505 * @param {Boolean} includeHidden True to include hidden column widths
58508 getTotalWidth : function(includeHidden){
58509 if(!this.totalWidth){
58510 this.totalWidth = 0;
58511 for(var i = 0, len = this.config.length; i < len; i++){
58512 if(includeHidden || !this.isHidden(i)){
58513 this.totalWidth += this.getColumnWidth(i);
58517 return this.totalWidth;
58521 * Returns the header for the specified column.
58522 * @param {Number} col The column index
58525 getColumnHeader : function(col){
58526 return this.config[col].header;
58530 * Sets the header for a column.
58531 * @param {Number} col The column index
58532 * @param {String} header The new header
58534 setColumnHeader : function(col, header){
58535 this.config[col].header = header;
58536 this.fireEvent("headerchange", this, col, header);
58540 * Returns the tooltip for the specified column.
58541 * @param {Number} col The column index
58544 getColumnTooltip : function(col){
58545 return this.config[col].tooltip;
58548 * Sets the tooltip for a column.
58549 * @param {Number} col The column index
58550 * @param {String} tooltip The new tooltip
58552 setColumnTooltip : function(col, tooltip){
58553 this.config[col].tooltip = tooltip;
58557 * Returns the dataIndex for the specified column.
58558 * @param {Number} col The column index
58561 getDataIndex : function(col){
58562 return this.config[col].dataIndex;
58566 * Sets the dataIndex for a column.
58567 * @param {Number} col The column index
58568 * @param {Number} dataIndex The new dataIndex
58570 setDataIndex : function(col, dataIndex){
58571 this.config[col].dataIndex = dataIndex;
58577 * Returns true if the cell is editable.
58578 * @param {Number} colIndex The column index
58579 * @param {Number} rowIndex The row index - this is nto actually used..?
58580 * @return {Boolean}
58582 isCellEditable : function(colIndex, rowIndex){
58583 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58587 * Returns the editor defined for the cell/column.
58588 * return false or null to disable editing.
58589 * @param {Number} colIndex The column index
58590 * @param {Number} rowIndex The row index
58593 getCellEditor : function(colIndex, rowIndex){
58594 return this.config[colIndex].editor;
58598 * Sets if a column is editable.
58599 * @param {Number} col The column index
58600 * @param {Boolean} editable True if the column is editable
58602 setEditable : function(col, editable){
58603 this.config[col].editable = editable;
58608 * Returns true if the column is hidden.
58609 * @param {Number} colIndex The column index
58610 * @return {Boolean}
58612 isHidden : function(colIndex){
58613 return this.config[colIndex].hidden;
58618 * Returns true if the column width cannot be changed
58620 isFixed : function(colIndex){
58621 return this.config[colIndex].fixed;
58625 * Returns true if the column can be resized
58626 * @return {Boolean}
58628 isResizable : function(colIndex){
58629 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58632 * Sets if a column is hidden.
58633 * @param {Number} colIndex The column index
58634 * @param {Boolean} hidden True if the column is hidden
58636 setHidden : function(colIndex, hidden){
58637 this.config[colIndex].hidden = hidden;
58638 this.totalWidth = null;
58639 this.fireEvent("hiddenchange", this, colIndex, hidden);
58643 * Sets the editor for a column.
58644 * @param {Number} col The column index
58645 * @param {Object} editor The editor object
58647 setEditor : function(col, editor){
58648 this.config[col].editor = editor;
58652 Roo.grid.ColumnModel.defaultRenderer = function(value)
58654 if(typeof value == "object") {
58657 if(typeof value == "string" && value.length < 1){
58661 return String.format("{0}", value);
58664 // Alias for backwards compatibility
58665 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
58668 * Ext JS Library 1.1.1
58669 * Copyright(c) 2006-2007, Ext JS, LLC.
58671 * Originally Released Under LGPL - original licence link has changed is not relivant.
58674 * <script type="text/javascript">
58678 * @class Roo.grid.AbstractSelectionModel
58679 * @extends Roo.util.Observable
58680 * Abstract base class for grid SelectionModels. It provides the interface that should be
58681 * implemented by descendant classes. This class should not be directly instantiated.
58684 Roo.grid.AbstractSelectionModel = function(){
58685 this.locked = false;
58686 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
58689 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
58690 /** @ignore Called by the grid automatically. Do not call directly. */
58691 init : function(grid){
58697 * Locks the selections.
58700 this.locked = true;
58704 * Unlocks the selections.
58706 unlock : function(){
58707 this.locked = false;
58711 * Returns true if the selections are locked.
58712 * @return {Boolean}
58714 isLocked : function(){
58715 return this.locked;
58719 * Ext JS Library 1.1.1
58720 * Copyright(c) 2006-2007, Ext JS, LLC.
58722 * Originally Released Under LGPL - original licence link has changed is not relivant.
58725 * <script type="text/javascript">
58728 * @extends Roo.grid.AbstractSelectionModel
58729 * @class Roo.grid.RowSelectionModel
58730 * The default SelectionModel used by {@link Roo.grid.Grid}.
58731 * It supports multiple selections and keyboard selection/navigation.
58733 * @param {Object} config
58735 Roo.grid.RowSelectionModel = function(config){
58736 Roo.apply(this, config);
58737 this.selections = new Roo.util.MixedCollection(false, function(o){
58742 this.lastActive = false;
58746 * @event selectionchange
58747 * Fires when the selection changes
58748 * @param {SelectionModel} this
58750 "selectionchange" : true,
58752 * @event afterselectionchange
58753 * Fires after the selection changes (eg. by key press or clicking)
58754 * @param {SelectionModel} this
58756 "afterselectionchange" : true,
58758 * @event beforerowselect
58759 * Fires when a row is selected being selected, return false to cancel.
58760 * @param {SelectionModel} this
58761 * @param {Number} rowIndex The selected index
58762 * @param {Boolean} keepExisting False if other selections will be cleared
58764 "beforerowselect" : true,
58767 * Fires when a row is selected.
58768 * @param {SelectionModel} this
58769 * @param {Number} rowIndex The selected index
58770 * @param {Roo.data.Record} r The record
58772 "rowselect" : true,
58774 * @event rowdeselect
58775 * Fires when a row is deselected.
58776 * @param {SelectionModel} this
58777 * @param {Number} rowIndex The selected index
58779 "rowdeselect" : true
58781 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
58782 this.locked = false;
58785 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
58787 * @cfg {Boolean} singleSelect
58788 * True to allow selection of only one row at a time (defaults to false)
58790 singleSelect : false,
58793 initEvents : function(){
58795 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
58796 this.grid.on("mousedown", this.handleMouseDown, this);
58797 }else{ // allow click to work like normal
58798 this.grid.on("rowclick", this.handleDragableRowClick, this);
58801 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
58802 "up" : function(e){
58804 this.selectPrevious(e.shiftKey);
58805 }else if(this.last !== false && this.lastActive !== false){
58806 var last = this.last;
58807 this.selectRange(this.last, this.lastActive-1);
58808 this.grid.getView().focusRow(this.lastActive);
58809 if(last !== false){
58813 this.selectFirstRow();
58815 this.fireEvent("afterselectionchange", this);
58817 "down" : function(e){
58819 this.selectNext(e.shiftKey);
58820 }else if(this.last !== false && this.lastActive !== false){
58821 var last = this.last;
58822 this.selectRange(this.last, this.lastActive+1);
58823 this.grid.getView().focusRow(this.lastActive);
58824 if(last !== false){
58828 this.selectFirstRow();
58830 this.fireEvent("afterselectionchange", this);
58835 var view = this.grid.view;
58836 view.on("refresh", this.onRefresh, this);
58837 view.on("rowupdated", this.onRowUpdated, this);
58838 view.on("rowremoved", this.onRemove, this);
58842 onRefresh : function(){
58843 var ds = this.grid.dataSource, i, v = this.grid.view;
58844 var s = this.selections;
58845 s.each(function(r){
58846 if((i = ds.indexOfId(r.id)) != -1){
58848 s.add(ds.getAt(i)); // updating the selection relate data
58856 onRemove : function(v, index, r){
58857 this.selections.remove(r);
58861 onRowUpdated : function(v, index, r){
58862 if(this.isSelected(r)){
58863 v.onRowSelect(index);
58869 * @param {Array} records The records to select
58870 * @param {Boolean} keepExisting (optional) True to keep existing selections
58872 selectRecords : function(records, keepExisting){
58874 this.clearSelections();
58876 var ds = this.grid.dataSource;
58877 for(var i = 0, len = records.length; i < len; i++){
58878 this.selectRow(ds.indexOf(records[i]), true);
58883 * Gets the number of selected rows.
58886 getCount : function(){
58887 return this.selections.length;
58891 * Selects the first row in the grid.
58893 selectFirstRow : function(){
58898 * Select the last row.
58899 * @param {Boolean} keepExisting (optional) True to keep existing selections
58901 selectLastRow : function(keepExisting){
58902 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
58906 * Selects the row immediately following the last selected row.
58907 * @param {Boolean} keepExisting (optional) True to keep existing selections
58909 selectNext : function(keepExisting){
58910 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
58911 this.selectRow(this.last+1, keepExisting);
58912 this.grid.getView().focusRow(this.last);
58917 * Selects the row that precedes the last selected row.
58918 * @param {Boolean} keepExisting (optional) True to keep existing selections
58920 selectPrevious : function(keepExisting){
58922 this.selectRow(this.last-1, keepExisting);
58923 this.grid.getView().focusRow(this.last);
58928 * Returns the selected records
58929 * @return {Array} Array of selected records
58931 getSelections : function(){
58932 return [].concat(this.selections.items);
58936 * Returns the first selected record.
58939 getSelected : function(){
58940 return this.selections.itemAt(0);
58945 * Clears all selections.
58947 clearSelections : function(fast){
58952 var ds = this.grid.dataSource;
58953 var s = this.selections;
58954 s.each(function(r){
58955 this.deselectRow(ds.indexOfId(r.id));
58959 this.selections.clear();
58966 * Selects all rows.
58968 selectAll : function(){
58972 this.selections.clear();
58973 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
58974 this.selectRow(i, true);
58979 * Returns True if there is a selection.
58980 * @return {Boolean}
58982 hasSelection : function(){
58983 return this.selections.length > 0;
58987 * Returns True if the specified row is selected.
58988 * @param {Number/Record} record The record or index of the record to check
58989 * @return {Boolean}
58991 isSelected : function(index){
58992 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
58993 return (r && this.selections.key(r.id) ? true : false);
58997 * Returns True if the specified record id is selected.
58998 * @param {String} id The id of record to check
58999 * @return {Boolean}
59001 isIdSelected : function(id){
59002 return (this.selections.key(id) ? true : false);
59006 handleMouseDown : function(e, t){
59007 var view = this.grid.getView(), rowIndex;
59008 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
59011 if(e.shiftKey && this.last !== false){
59012 var last = this.last;
59013 this.selectRange(last, rowIndex, e.ctrlKey);
59014 this.last = last; // reset the last
59015 view.focusRow(rowIndex);
59017 var isSelected = this.isSelected(rowIndex);
59018 if(e.button !== 0 && isSelected){
59019 view.focusRow(rowIndex);
59020 }else if(e.ctrlKey && isSelected){
59021 this.deselectRow(rowIndex);
59022 }else if(!isSelected){
59023 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
59024 view.focusRow(rowIndex);
59027 this.fireEvent("afterselectionchange", this);
59030 handleDragableRowClick : function(grid, rowIndex, e)
59032 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
59033 this.selectRow(rowIndex, false);
59034 grid.view.focusRow(rowIndex);
59035 this.fireEvent("afterselectionchange", this);
59040 * Selects multiple rows.
59041 * @param {Array} rows Array of the indexes of the row to select
59042 * @param {Boolean} keepExisting (optional) True to keep existing selections
59044 selectRows : function(rows, keepExisting){
59046 this.clearSelections();
59048 for(var i = 0, len = rows.length; i < len; i++){
59049 this.selectRow(rows[i], true);
59054 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59055 * @param {Number} startRow The index of the first row in the range
59056 * @param {Number} endRow The index of the last row in the range
59057 * @param {Boolean} keepExisting (optional) True to retain existing selections
59059 selectRange : function(startRow, endRow, keepExisting){
59064 this.clearSelections();
59066 if(startRow <= endRow){
59067 for(var i = startRow; i <= endRow; i++){
59068 this.selectRow(i, true);
59071 for(var i = startRow; i >= endRow; i--){
59072 this.selectRow(i, true);
59078 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59079 * @param {Number} startRow The index of the first row in the range
59080 * @param {Number} endRow The index of the last row in the range
59082 deselectRange : function(startRow, endRow, preventViewNotify){
59086 for(var i = startRow; i <= endRow; i++){
59087 this.deselectRow(i, preventViewNotify);
59093 * @param {Number} row The index of the row to select
59094 * @param {Boolean} keepExisting (optional) True to keep existing selections
59096 selectRow : function(index, keepExisting, preventViewNotify){
59097 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
59100 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59101 if(!keepExisting || this.singleSelect){
59102 this.clearSelections();
59104 var r = this.grid.dataSource.getAt(index);
59105 this.selections.add(r);
59106 this.last = this.lastActive = index;
59107 if(!preventViewNotify){
59108 this.grid.getView().onRowSelect(index);
59110 this.fireEvent("rowselect", this, index, r);
59111 this.fireEvent("selectionchange", this);
59117 * @param {Number} row The index of the row to deselect
59119 deselectRow : function(index, preventViewNotify){
59123 if(this.last == index){
59126 if(this.lastActive == index){
59127 this.lastActive = false;
59129 var r = this.grid.dataSource.getAt(index);
59130 this.selections.remove(r);
59131 if(!preventViewNotify){
59132 this.grid.getView().onRowDeselect(index);
59134 this.fireEvent("rowdeselect", this, index);
59135 this.fireEvent("selectionchange", this);
59139 restoreLast : function(){
59141 this.last = this._last;
59146 acceptsNav : function(row, col, cm){
59147 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59151 onEditorKey : function(field, e){
59152 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59157 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59159 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59161 }else if(k == e.ENTER && !e.ctrlKey){
59165 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59167 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59169 }else if(k == e.ESC){
59173 g.startEditing(newCell[0], newCell[1]);
59178 * Ext JS Library 1.1.1
59179 * Copyright(c) 2006-2007, Ext JS, LLC.
59181 * Originally Released Under LGPL - original licence link has changed is not relivant.
59184 * <script type="text/javascript">
59187 * @class Roo.grid.CellSelectionModel
59188 * @extends Roo.grid.AbstractSelectionModel
59189 * This class provides the basic implementation for cell selection in a grid.
59191 * @param {Object} config The object containing the configuration of this model.
59192 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59194 Roo.grid.CellSelectionModel = function(config){
59195 Roo.apply(this, config);
59197 this.selection = null;
59201 * @event beforerowselect
59202 * Fires before a cell is selected.
59203 * @param {SelectionModel} this
59204 * @param {Number} rowIndex The selected row index
59205 * @param {Number} colIndex The selected cell index
59207 "beforecellselect" : true,
59209 * @event cellselect
59210 * Fires when a cell is selected.
59211 * @param {SelectionModel} this
59212 * @param {Number} rowIndex The selected row index
59213 * @param {Number} colIndex The selected cell index
59215 "cellselect" : true,
59217 * @event selectionchange
59218 * Fires when the active selection changes.
59219 * @param {SelectionModel} this
59220 * @param {Object} selection null for no selection or an object (o) with two properties
59222 <li>o.record: the record object for the row the selection is in</li>
59223 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59226 "selectionchange" : true,
59229 * Fires when the tab (or enter) was pressed on the last editable cell
59230 * You can use this to trigger add new row.
59231 * @param {SelectionModel} this
59235 * @event beforeeditnext
59236 * Fires before the next editable sell is made active
59237 * You can use this to skip to another cell or fire the tabend
59238 * if you set cell to false
59239 * @param {Object} eventdata object : { cell : [ row, col ] }
59241 "beforeeditnext" : true
59243 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59246 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59248 enter_is_tab: false,
59251 initEvents : function(){
59252 this.grid.on("mousedown", this.handleMouseDown, this);
59253 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59254 var view = this.grid.view;
59255 view.on("refresh", this.onViewChange, this);
59256 view.on("rowupdated", this.onRowUpdated, this);
59257 view.on("beforerowremoved", this.clearSelections, this);
59258 view.on("beforerowsinserted", this.clearSelections, this);
59259 if(this.grid.isEditor){
59260 this.grid.on("beforeedit", this.beforeEdit, this);
59265 beforeEdit : function(e){
59266 this.select(e.row, e.column, false, true, e.record);
59270 onRowUpdated : function(v, index, r){
59271 if(this.selection && this.selection.record == r){
59272 v.onCellSelect(index, this.selection.cell[1]);
59277 onViewChange : function(){
59278 this.clearSelections(true);
59282 * Returns the currently selected cell,.
59283 * @return {Array} The selected cell (row, column) or null if none selected.
59285 getSelectedCell : function(){
59286 return this.selection ? this.selection.cell : null;
59290 * Clears all selections.
59291 * @param {Boolean} true to prevent the gridview from being notified about the change.
59293 clearSelections : function(preventNotify){
59294 var s = this.selection;
59296 if(preventNotify !== true){
59297 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59299 this.selection = null;
59300 this.fireEvent("selectionchange", this, null);
59305 * Returns true if there is a selection.
59306 * @return {Boolean}
59308 hasSelection : function(){
59309 return this.selection ? true : false;
59313 handleMouseDown : function(e, t){
59314 var v = this.grid.getView();
59315 if(this.isLocked()){
59318 var row = v.findRowIndex(t);
59319 var cell = v.findCellIndex(t);
59320 if(row !== false && cell !== false){
59321 this.select(row, cell);
59327 * @param {Number} rowIndex
59328 * @param {Number} collIndex
59330 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59331 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59332 this.clearSelections();
59333 r = r || this.grid.dataSource.getAt(rowIndex);
59336 cell : [rowIndex, colIndex]
59338 if(!preventViewNotify){
59339 var v = this.grid.getView();
59340 v.onCellSelect(rowIndex, colIndex);
59341 if(preventFocus !== true){
59342 v.focusCell(rowIndex, colIndex);
59345 this.fireEvent("cellselect", this, rowIndex, colIndex);
59346 this.fireEvent("selectionchange", this, this.selection);
59351 isSelectable : function(rowIndex, colIndex, cm){
59352 return !cm.isHidden(colIndex);
59356 handleKeyDown : function(e){
59357 //Roo.log('Cell Sel Model handleKeyDown');
59358 if(!e.isNavKeyPress()){
59361 var g = this.grid, s = this.selection;
59364 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59366 this.select(cell[0], cell[1]);
59371 var walk = function(row, col, step){
59372 return g.walkCells(row, col, step, sm.isSelectable, sm);
59374 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59381 // handled by onEditorKey
59382 if (g.isEditor && g.editing) {
59386 newCell = walk(r, c-1, -1);
59388 newCell = walk(r, c+1, 1);
59393 newCell = walk(r+1, c, 1);
59397 newCell = walk(r-1, c, -1);
59401 newCell = walk(r, c+1, 1);
59405 newCell = walk(r, c-1, -1);
59410 if(g.isEditor && !g.editing){
59411 g.startEditing(r, c);
59420 this.select(newCell[0], newCell[1]);
59426 acceptsNav : function(row, col, cm){
59427 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59431 * @param {Number} field (not used) - as it's normally used as a listener
59432 * @param {Number} e - event - fake it by using
59434 * var e = Roo.EventObjectImpl.prototype;
59435 * e.keyCode = e.TAB
59439 onEditorKey : function(field, e){
59441 var k = e.getKey(),
59444 ed = g.activeEditor,
59446 ///Roo.log('onEditorKey' + k);
59449 if (this.enter_is_tab && k == e.ENTER) {
59455 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59457 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59463 } else if(k == e.ENTER && !e.ctrlKey){
59466 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59468 } else if(k == e.ESC){
59473 var ecall = { cell : newCell, forward : forward };
59474 this.fireEvent('beforeeditnext', ecall );
59475 newCell = ecall.cell;
59476 forward = ecall.forward;
59480 //Roo.log('next cell after edit');
59481 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59482 } else if (forward) {
59483 // tabbed past last
59484 this.fireEvent.defer(100, this, ['tabend',this]);
59489 * Ext JS Library 1.1.1
59490 * Copyright(c) 2006-2007, Ext JS, LLC.
59492 * Originally Released Under LGPL - original licence link has changed is not relivant.
59495 * <script type="text/javascript">
59499 * @class Roo.grid.EditorGrid
59500 * @extends Roo.grid.Grid
59501 * Class for creating and editable grid.
59502 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59503 * The container MUST have some type of size defined for the grid to fill. The container will be
59504 * automatically set to position relative if it isn't already.
59505 * @param {Object} dataSource The data model to bind to
59506 * @param {Object} colModel The column model with info about this grid's columns
59508 Roo.grid.EditorGrid = function(container, config){
59509 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59510 this.getGridEl().addClass("xedit-grid");
59512 if(!this.selModel){
59513 this.selModel = new Roo.grid.CellSelectionModel();
59516 this.activeEditor = null;
59520 * @event beforeedit
59521 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59522 * <ul style="padding:5px;padding-left:16px;">
59523 * <li>grid - This grid</li>
59524 * <li>record - The record being edited</li>
59525 * <li>field - The field name being edited</li>
59526 * <li>value - The value for the field being edited.</li>
59527 * <li>row - The grid row index</li>
59528 * <li>column - The grid column index</li>
59529 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59531 * @param {Object} e An edit event (see above for description)
59533 "beforeedit" : true,
59536 * Fires after a cell is edited. <br />
59537 * <ul style="padding:5px;padding-left:16px;">
59538 * <li>grid - This grid</li>
59539 * <li>record - The record being edited</li>
59540 * <li>field - The field name being edited</li>
59541 * <li>value - The value being set</li>
59542 * <li>originalValue - The original value for the field, before the edit.</li>
59543 * <li>row - The grid row index</li>
59544 * <li>column - The grid column index</li>
59546 * @param {Object} e An edit event (see above for description)
59548 "afteredit" : true,
59550 * @event validateedit
59551 * Fires after a cell is edited, but before the value is set in the record.
59552 * You can use this to modify the value being set in the field, Return false
59553 * to cancel the change. The edit event object has the following properties <br />
59554 * <ul style="padding:5px;padding-left:16px;">
59555 * <li>editor - This editor</li>
59556 * <li>grid - This grid</li>
59557 * <li>record - The record being edited</li>
59558 * <li>field - The field name being edited</li>
59559 * <li>value - The value being set</li>
59560 * <li>originalValue - The original value for the field, before the edit.</li>
59561 * <li>row - The grid row index</li>
59562 * <li>column - The grid column index</li>
59563 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59565 * @param {Object} e An edit event (see above for description)
59567 "validateedit" : true
59569 this.on("bodyscroll", this.stopEditing, this);
59570 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59573 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59575 * @cfg {Number} clicksToEdit
59576 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59583 trackMouseOver: false, // causes very odd FF errors
59585 onCellDblClick : function(g, row, col){
59586 this.startEditing(row, col);
59589 onEditComplete : function(ed, value, startValue){
59590 this.editing = false;
59591 this.activeEditor = null;
59592 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59594 var field = this.colModel.getDataIndex(ed.col);
59599 originalValue: startValue,
59606 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59609 if(String(value) !== String(startValue)){
59611 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59612 r.set(field, e.value);
59613 // if we are dealing with a combo box..
59614 // then we also set the 'name' colum to be the displayField
59615 if (ed.field.displayField && ed.field.name) {
59616 r.set(ed.field.name, ed.field.el.dom.value);
59619 delete e.cancel; //?? why!!!
59620 this.fireEvent("afteredit", e);
59623 this.fireEvent("afteredit", e); // always fire it!
59625 this.view.focusCell(ed.row, ed.col);
59629 * Starts editing the specified for the specified row/column
59630 * @param {Number} rowIndex
59631 * @param {Number} colIndex
59633 startEditing : function(row, col){
59634 this.stopEditing();
59635 if(this.colModel.isCellEditable(col, row)){
59636 this.view.ensureVisible(row, col, true);
59638 var r = this.dataSource.getAt(row);
59639 var field = this.colModel.getDataIndex(col);
59640 var cell = Roo.get(this.view.getCell(row,col));
59645 value: r.data[field],
59650 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59651 this.editing = true;
59652 var ed = this.colModel.getCellEditor(col, row);
59658 ed.render(ed.parentEl || document.body);
59664 (function(){ // complex but required for focus issues in safari, ie and opera
59668 ed.on("complete", this.onEditComplete, this, {single: true});
59669 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
59670 this.activeEditor = ed;
59671 var v = r.data[field];
59672 ed.startEdit(this.view.getCell(row, col), v);
59673 // combo's with 'displayField and name set
59674 if (ed.field.displayField && ed.field.name) {
59675 ed.field.el.dom.value = r.data[ed.field.name];
59679 }).defer(50, this);
59685 * Stops any active editing
59687 stopEditing : function(){
59688 if(this.activeEditor){
59689 this.activeEditor.completeEdit();
59691 this.activeEditor = null;
59695 * Called to get grid's drag proxy text, by default returns this.ddText.
59698 getDragDropText : function(){
59699 var count = this.selModel.getSelectedCell() ? 1 : 0;
59700 return String.format(this.ddText, count, count == 1 ? '' : 's');
59705 * Ext JS Library 1.1.1
59706 * Copyright(c) 2006-2007, Ext JS, LLC.
59708 * Originally Released Under LGPL - original licence link has changed is not relivant.
59711 * <script type="text/javascript">
59714 // private - not really -- you end up using it !
59715 // This is a support class used internally by the Grid components
59718 * @class Roo.grid.GridEditor
59719 * @extends Roo.Editor
59720 * Class for creating and editable grid elements.
59721 * @param {Object} config any settings (must include field)
59723 Roo.grid.GridEditor = function(field, config){
59724 if (!config && field.field) {
59726 field = Roo.factory(config.field, Roo.form);
59728 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
59729 field.monitorTab = false;
59732 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
59735 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
59738 alignment: "tl-tl",
59741 cls: "x-small-editor x-grid-editor",
59746 * Ext JS Library 1.1.1
59747 * Copyright(c) 2006-2007, Ext JS, LLC.
59749 * Originally Released Under LGPL - original licence link has changed is not relivant.
59752 * <script type="text/javascript">
59757 Roo.grid.PropertyRecord = Roo.data.Record.create([
59758 {name:'name',type:'string'}, 'value'
59762 Roo.grid.PropertyStore = function(grid, source){
59764 this.store = new Roo.data.Store({
59765 recordType : Roo.grid.PropertyRecord
59767 this.store.on('update', this.onUpdate, this);
59769 this.setSource(source);
59771 Roo.grid.PropertyStore.superclass.constructor.call(this);
59776 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
59777 setSource : function(o){
59779 this.store.removeAll();
59782 if(this.isEditableValue(o[k])){
59783 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
59786 this.store.loadRecords({records: data}, {}, true);
59789 onUpdate : function(ds, record, type){
59790 if(type == Roo.data.Record.EDIT){
59791 var v = record.data['value'];
59792 var oldValue = record.modified['value'];
59793 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
59794 this.source[record.id] = v;
59796 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
59803 getProperty : function(row){
59804 return this.store.getAt(row);
59807 isEditableValue: function(val){
59808 if(val && val instanceof Date){
59810 }else if(typeof val == 'object' || typeof val == 'function'){
59816 setValue : function(prop, value){
59817 this.source[prop] = value;
59818 this.store.getById(prop).set('value', value);
59821 getSource : function(){
59822 return this.source;
59826 Roo.grid.PropertyColumnModel = function(grid, store){
59829 g.PropertyColumnModel.superclass.constructor.call(this, [
59830 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
59831 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
59833 this.store = store;
59834 this.bselect = Roo.DomHelper.append(document.body, {
59835 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
59836 {tag: 'option', value: 'true', html: 'true'},
59837 {tag: 'option', value: 'false', html: 'false'}
59840 Roo.id(this.bselect);
59843 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
59844 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
59845 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
59846 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
59847 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
59849 this.renderCellDelegate = this.renderCell.createDelegate(this);
59850 this.renderPropDelegate = this.renderProp.createDelegate(this);
59853 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
59857 valueText : 'Value',
59859 dateFormat : 'm/j/Y',
59862 renderDate : function(dateVal){
59863 return dateVal.dateFormat(this.dateFormat);
59866 renderBool : function(bVal){
59867 return bVal ? 'true' : 'false';
59870 isCellEditable : function(colIndex, rowIndex){
59871 return colIndex == 1;
59874 getRenderer : function(col){
59876 this.renderCellDelegate : this.renderPropDelegate;
59879 renderProp : function(v){
59880 return this.getPropertyName(v);
59883 renderCell : function(val){
59885 if(val instanceof Date){
59886 rv = this.renderDate(val);
59887 }else if(typeof val == 'boolean'){
59888 rv = this.renderBool(val);
59890 return Roo.util.Format.htmlEncode(rv);
59893 getPropertyName : function(name){
59894 var pn = this.grid.propertyNames;
59895 return pn && pn[name] ? pn[name] : name;
59898 getCellEditor : function(colIndex, rowIndex){
59899 var p = this.store.getProperty(rowIndex);
59900 var n = p.data['name'], val = p.data['value'];
59902 if(typeof(this.grid.customEditors[n]) == 'string'){
59903 return this.editors[this.grid.customEditors[n]];
59905 if(typeof(this.grid.customEditors[n]) != 'undefined'){
59906 return this.grid.customEditors[n];
59908 if(val instanceof Date){
59909 return this.editors['date'];
59910 }else if(typeof val == 'number'){
59911 return this.editors['number'];
59912 }else if(typeof val == 'boolean'){
59913 return this.editors['boolean'];
59915 return this.editors['string'];
59921 * @class Roo.grid.PropertyGrid
59922 * @extends Roo.grid.EditorGrid
59923 * This class represents the interface of a component based property grid control.
59924 * <br><br>Usage:<pre><code>
59925 var grid = new Roo.grid.PropertyGrid("my-container-id", {
59933 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59934 * The container MUST have some type of size defined for the grid to fill. The container will be
59935 * automatically set to position relative if it isn't already.
59936 * @param {Object} config A config object that sets properties on this grid.
59938 Roo.grid.PropertyGrid = function(container, config){
59939 config = config || {};
59940 var store = new Roo.grid.PropertyStore(this);
59941 this.store = store;
59942 var cm = new Roo.grid.PropertyColumnModel(this, store);
59943 store.store.sort('name', 'ASC');
59944 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
59947 enableColLock:false,
59948 enableColumnMove:false,
59950 trackMouseOver: false,
59953 this.getGridEl().addClass('x-props-grid');
59954 this.lastEditRow = null;
59955 this.on('columnresize', this.onColumnResize, this);
59958 * @event beforepropertychange
59959 * Fires before a property changes (return false to stop?)
59960 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
59961 * @param {String} id Record Id
59962 * @param {String} newval New Value
59963 * @param {String} oldval Old Value
59965 "beforepropertychange": true,
59967 * @event propertychange
59968 * Fires after a property changes
59969 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
59970 * @param {String} id Record Id
59971 * @param {String} newval New Value
59972 * @param {String} oldval Old Value
59974 "propertychange": true
59976 this.customEditors = this.customEditors || {};
59978 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
59981 * @cfg {Object} customEditors map of colnames=> custom editors.
59982 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
59983 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
59984 * false disables editing of the field.
59988 * @cfg {Object} propertyNames map of property Names to their displayed value
59991 render : function(){
59992 Roo.grid.PropertyGrid.superclass.render.call(this);
59993 this.autoSize.defer(100, this);
59996 autoSize : function(){
59997 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
59999 this.view.fitColumns();
60003 onColumnResize : function(){
60004 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
60008 * Sets the data for the Grid
60009 * accepts a Key => Value object of all the elements avaiable.
60010 * @param {Object} data to appear in grid.
60012 setSource : function(source){
60013 this.store.setSource(source);
60017 * Gets all the data from the grid.
60018 * @return {Object} data data stored in grid
60020 getSource : function(){
60021 return this.store.getSource();
60030 * @class Roo.grid.Calendar
60031 * @extends Roo.util.Grid
60032 * This class extends the Grid to provide a calendar widget
60033 * <br><br>Usage:<pre><code>
60034 var grid = new Roo.grid.Calendar("my-container-id", {
60037 selModel: mySelectionModel,
60038 autoSizeColumns: true,
60039 monitorWindowResize: false,
60040 trackMouseOver: true
60041 eventstore : real data store..
60047 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60048 * The container MUST have some type of size defined for the grid to fill. The container will be
60049 * automatically set to position relative if it isn't already.
60050 * @param {Object} config A config object that sets properties on this grid.
60052 Roo.grid.Calendar = function(container, config){
60053 // initialize the container
60054 this.container = Roo.get(container);
60055 this.container.update("");
60056 this.container.setStyle("overflow", "hidden");
60057 this.container.addClass('x-grid-container');
60059 this.id = this.container.id;
60061 Roo.apply(this, config);
60062 // check and correct shorthanded configs
60066 for (var r = 0;r < 6;r++) {
60069 for (var c =0;c < 7;c++) {
60073 if (this.eventStore) {
60074 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60075 this.eventStore.on('load',this.onLoad, this);
60076 this.eventStore.on('beforeload',this.clearEvents, this);
60080 this.dataSource = new Roo.data.Store({
60081 proxy: new Roo.data.MemoryProxy(rows),
60082 reader: new Roo.data.ArrayReader({}, [
60083 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60086 this.dataSource.load();
60087 this.ds = this.dataSource;
60088 this.ds.xmodule = this.xmodule || false;
60091 var cellRender = function(v,x,r)
60093 return String.format(
60094 '<div class="fc-day fc-widget-content"><div>' +
60095 '<div class="fc-event-container"></div>' +
60096 '<div class="fc-day-number">{0}</div>'+
60098 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60099 '</div></div>', v);
60104 this.colModel = new Roo.grid.ColumnModel( [
60106 xtype: 'ColumnModel',
60108 dataIndex : 'weekday0',
60110 renderer : cellRender
60113 xtype: 'ColumnModel',
60115 dataIndex : 'weekday1',
60117 renderer : cellRender
60120 xtype: 'ColumnModel',
60122 dataIndex : 'weekday2',
60123 header : 'Tuesday',
60124 renderer : cellRender
60127 xtype: 'ColumnModel',
60129 dataIndex : 'weekday3',
60130 header : 'Wednesday',
60131 renderer : cellRender
60134 xtype: 'ColumnModel',
60136 dataIndex : 'weekday4',
60137 header : 'Thursday',
60138 renderer : cellRender
60141 xtype: 'ColumnModel',
60143 dataIndex : 'weekday5',
60145 renderer : cellRender
60148 xtype: 'ColumnModel',
60150 dataIndex : 'weekday6',
60151 header : 'Saturday',
60152 renderer : cellRender
60155 this.cm = this.colModel;
60156 this.cm.xmodule = this.xmodule || false;
60160 //this.selModel = new Roo.grid.CellSelectionModel();
60161 //this.sm = this.selModel;
60162 //this.selModel.init(this);
60166 this.container.setWidth(this.width);
60170 this.container.setHeight(this.height);
60177 * The raw click event for the entire grid.
60178 * @param {Roo.EventObject} e
60183 * The raw dblclick event for the entire grid.
60184 * @param {Roo.EventObject} e
60188 * @event contextmenu
60189 * The raw contextmenu event for the entire grid.
60190 * @param {Roo.EventObject} e
60192 "contextmenu" : true,
60195 * The raw mousedown event for the entire grid.
60196 * @param {Roo.EventObject} e
60198 "mousedown" : true,
60201 * The raw mouseup event for the entire grid.
60202 * @param {Roo.EventObject} e
60207 * The raw mouseover event for the entire grid.
60208 * @param {Roo.EventObject} e
60210 "mouseover" : true,
60213 * The raw mouseout event for the entire grid.
60214 * @param {Roo.EventObject} e
60219 * The raw keypress event for the entire grid.
60220 * @param {Roo.EventObject} e
60225 * The raw keydown event for the entire grid.
60226 * @param {Roo.EventObject} e
60234 * Fires when a cell is clicked
60235 * @param {Grid} this
60236 * @param {Number} rowIndex
60237 * @param {Number} columnIndex
60238 * @param {Roo.EventObject} e
60240 "cellclick" : true,
60242 * @event celldblclick
60243 * Fires when a cell is double clicked
60244 * @param {Grid} this
60245 * @param {Number} rowIndex
60246 * @param {Number} columnIndex
60247 * @param {Roo.EventObject} e
60249 "celldblclick" : true,
60252 * Fires when a row is clicked
60253 * @param {Grid} this
60254 * @param {Number} rowIndex
60255 * @param {Roo.EventObject} e
60259 * @event rowdblclick
60260 * Fires when a row is double clicked
60261 * @param {Grid} this
60262 * @param {Number} rowIndex
60263 * @param {Roo.EventObject} e
60265 "rowdblclick" : true,
60267 * @event headerclick
60268 * Fires when a header is clicked
60269 * @param {Grid} this
60270 * @param {Number} columnIndex
60271 * @param {Roo.EventObject} e
60273 "headerclick" : true,
60275 * @event headerdblclick
60276 * Fires when a header cell is double clicked
60277 * @param {Grid} this
60278 * @param {Number} columnIndex
60279 * @param {Roo.EventObject} e
60281 "headerdblclick" : true,
60283 * @event rowcontextmenu
60284 * Fires when a row is right clicked
60285 * @param {Grid} this
60286 * @param {Number} rowIndex
60287 * @param {Roo.EventObject} e
60289 "rowcontextmenu" : true,
60291 * @event cellcontextmenu
60292 * Fires when a cell is right clicked
60293 * @param {Grid} this
60294 * @param {Number} rowIndex
60295 * @param {Number} cellIndex
60296 * @param {Roo.EventObject} e
60298 "cellcontextmenu" : true,
60300 * @event headercontextmenu
60301 * Fires when a header is right clicked
60302 * @param {Grid} this
60303 * @param {Number} columnIndex
60304 * @param {Roo.EventObject} e
60306 "headercontextmenu" : true,
60308 * @event bodyscroll
60309 * Fires when the body element is scrolled
60310 * @param {Number} scrollLeft
60311 * @param {Number} scrollTop
60313 "bodyscroll" : true,
60315 * @event columnresize
60316 * Fires when the user resizes a column
60317 * @param {Number} columnIndex
60318 * @param {Number} newSize
60320 "columnresize" : true,
60322 * @event columnmove
60323 * Fires when the user moves a column
60324 * @param {Number} oldIndex
60325 * @param {Number} newIndex
60327 "columnmove" : true,
60330 * Fires when row(s) start being dragged
60331 * @param {Grid} this
60332 * @param {Roo.GridDD} dd The drag drop object
60333 * @param {event} e The raw browser event
60335 "startdrag" : true,
60338 * Fires when a drag operation is complete
60339 * @param {Grid} this
60340 * @param {Roo.GridDD} dd The drag drop object
60341 * @param {event} e The raw browser event
60346 * Fires when dragged row(s) are dropped on a valid DD target
60347 * @param {Grid} this
60348 * @param {Roo.GridDD} dd The drag drop object
60349 * @param {String} targetId The target drag drop object
60350 * @param {event} e The raw browser event
60355 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60356 * @param {Grid} this
60357 * @param {Roo.GridDD} dd The drag drop object
60358 * @param {String} targetId The target drag drop object
60359 * @param {event} e The raw browser event
60364 * Fires when the dragged row(s) first cross another DD target while being dragged
60365 * @param {Grid} this
60366 * @param {Roo.GridDD} dd The drag drop object
60367 * @param {String} targetId The target drag drop object
60368 * @param {event} e The raw browser event
60370 "dragenter" : true,
60373 * Fires when the dragged row(s) leave another DD target while being dragged
60374 * @param {Grid} this
60375 * @param {Roo.GridDD} dd The drag drop object
60376 * @param {String} targetId The target drag drop object
60377 * @param {event} e The raw browser event
60382 * Fires when a row is rendered, so you can change add a style to it.
60383 * @param {GridView} gridview The grid view
60384 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60390 * Fires when the grid is rendered
60391 * @param {Grid} grid
60396 * Fires when a date is selected
60397 * @param {DatePicker} this
60398 * @param {Date} date The selected date
60402 * @event monthchange
60403 * Fires when the displayed month changes
60404 * @param {DatePicker} this
60405 * @param {Date} date The selected month
60407 'monthchange': true,
60409 * @event evententer
60410 * Fires when mouse over an event
60411 * @param {Calendar} this
60412 * @param {event} Event
60414 'evententer': true,
60416 * @event eventleave
60417 * Fires when the mouse leaves an
60418 * @param {Calendar} this
60421 'eventleave': true,
60423 * @event eventclick
60424 * Fires when the mouse click an
60425 * @param {Calendar} this
60428 'eventclick': true,
60430 * @event eventrender
60431 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60432 * @param {Calendar} this
60433 * @param {data} data to be modified
60435 'eventrender': true
60439 Roo.grid.Grid.superclass.constructor.call(this);
60440 this.on('render', function() {
60441 this.view.el.addClass('x-grid-cal');
60443 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60447 if (!Roo.grid.Calendar.style) {
60448 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60451 '.x-grid-cal .x-grid-col' : {
60452 height: 'auto !important',
60453 'vertical-align': 'top'
60455 '.x-grid-cal .fc-event-hori' : {
60466 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60468 * @cfg {Store} eventStore The store that loads events.
60473 activeDate : false,
60476 monitorWindowResize : false,
60479 resizeColumns : function() {
60480 var col = (this.view.el.getWidth() / 7) - 3;
60481 // loop through cols, and setWidth
60482 for(var i =0 ; i < 7 ; i++){
60483 this.cm.setColumnWidth(i, col);
60486 setDate :function(date) {
60488 Roo.log('setDate?');
60490 this.resizeColumns();
60491 var vd = this.activeDate;
60492 this.activeDate = date;
60493 // if(vd && this.el){
60494 // var t = date.getTime();
60495 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60496 // Roo.log('using add remove');
60498 // this.fireEvent('monthchange', this, date);
60500 // this.cells.removeClass("fc-state-highlight");
60501 // this.cells.each(function(c){
60502 // if(c.dateValue == t){
60503 // c.addClass("fc-state-highlight");
60504 // setTimeout(function(){
60505 // try{c.dom.firstChild.focus();}catch(e){}
60515 var days = date.getDaysInMonth();
60517 var firstOfMonth = date.getFirstDateOfMonth();
60518 var startingPos = firstOfMonth.getDay()-this.startDay;
60520 if(startingPos < this.startDay){
60524 var pm = date.add(Date.MONTH, -1);
60525 var prevStart = pm.getDaysInMonth()-startingPos;
60529 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60531 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60532 //this.cells.addClassOnOver('fc-state-hover');
60534 var cells = this.cells.elements;
60535 var textEls = this.textNodes;
60537 //Roo.each(cells, function(cell){
60538 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60541 days += startingPos;
60543 // convert everything to numbers so it's fast
60544 var day = 86400000;
60545 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60548 //Roo.log(prevStart);
60550 var today = new Date().clearTime().getTime();
60551 var sel = date.clearTime().getTime();
60552 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60553 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60554 var ddMatch = this.disabledDatesRE;
60555 var ddText = this.disabledDatesText;
60556 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60557 var ddaysText = this.disabledDaysText;
60558 var format = this.format;
60560 var setCellClass = function(cal, cell){
60562 //Roo.log('set Cell Class');
60564 var t = d.getTime();
60569 cell.dateValue = t;
60571 cell.className += " fc-today";
60572 cell.className += " fc-state-highlight";
60573 cell.title = cal.todayText;
60576 // disable highlight in other month..
60577 cell.className += " fc-state-highlight";
60582 //cell.className = " fc-state-disabled";
60583 cell.title = cal.minText;
60587 //cell.className = " fc-state-disabled";
60588 cell.title = cal.maxText;
60592 if(ddays.indexOf(d.getDay()) != -1){
60593 // cell.title = ddaysText;
60594 // cell.className = " fc-state-disabled";
60597 if(ddMatch && format){
60598 var fvalue = d.dateFormat(format);
60599 if(ddMatch.test(fvalue)){
60600 cell.title = ddText.replace("%0", fvalue);
60601 cell.className = " fc-state-disabled";
60605 if (!cell.initialClassName) {
60606 cell.initialClassName = cell.dom.className;
60609 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60614 for(; i < startingPos; i++) {
60615 cells[i].dayName = (++prevStart);
60616 Roo.log(textEls[i]);
60617 d.setDate(d.getDate()+1);
60619 //cells[i].className = "fc-past fc-other-month";
60620 setCellClass(this, cells[i]);
60625 for(; i < days; i++){
60626 intDay = i - startingPos + 1;
60627 cells[i].dayName = (intDay);
60628 d.setDate(d.getDate()+1);
60630 cells[i].className = ''; // "x-date-active";
60631 setCellClass(this, cells[i]);
60635 for(; i < 42; i++) {
60636 //textEls[i].innerHTML = (++extraDays);
60638 d.setDate(d.getDate()+1);
60639 cells[i].dayName = (++extraDays);
60640 cells[i].className = "fc-future fc-other-month";
60641 setCellClass(this, cells[i]);
60644 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60646 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60648 // this will cause all the cells to mis
60651 for (var r = 0;r < 6;r++) {
60652 for (var c =0;c < 7;c++) {
60653 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60657 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60658 for(i=0;i<cells.length;i++) {
60660 this.cells.elements[i].dayName = cells[i].dayName ;
60661 this.cells.elements[i].className = cells[i].className;
60662 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
60663 this.cells.elements[i].title = cells[i].title ;
60664 this.cells.elements[i].dateValue = cells[i].dateValue ;
60670 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
60671 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
60673 ////if(totalRows != 6){
60674 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
60675 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
60678 this.fireEvent('monthchange', this, date);
60683 * Returns the grid's SelectionModel.
60684 * @return {SelectionModel}
60686 getSelectionModel : function(){
60687 if(!this.selModel){
60688 this.selModel = new Roo.grid.CellSelectionModel();
60690 return this.selModel;
60694 this.eventStore.load()
60700 findCell : function(dt) {
60701 dt = dt.clearTime().getTime();
60703 this.cells.each(function(c){
60704 //Roo.log("check " +c.dateValue + '?=' + dt);
60705 if(c.dateValue == dt){
60715 findCells : function(rec) {
60716 var s = rec.data.start_dt.clone().clearTime().getTime();
60718 var e= rec.data.end_dt.clone().clearTime().getTime();
60721 this.cells.each(function(c){
60722 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
60724 if(c.dateValue > e){
60727 if(c.dateValue < s){
60736 findBestRow: function(cells)
60740 for (var i =0 ; i < cells.length;i++) {
60741 ret = Math.max(cells[i].rows || 0,ret);
60748 addItem : function(rec)
60750 // look for vertical location slot in
60751 var cells = this.findCells(rec);
60753 rec.row = this.findBestRow(cells);
60755 // work out the location.
60759 for(var i =0; i < cells.length; i++) {
60767 if (crow.start.getY() == cells[i].getY()) {
60769 crow.end = cells[i];
60785 for (var i = 0; i < cells.length;i++) {
60786 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
60793 clearEvents: function() {
60795 if (!this.eventStore.getCount()) {
60798 // reset number of rows in cells.
60799 Roo.each(this.cells.elements, function(c){
60803 this.eventStore.each(function(e) {
60804 this.clearEvent(e);
60809 clearEvent : function(ev)
60812 Roo.each(ev.els, function(el) {
60813 el.un('mouseenter' ,this.onEventEnter, this);
60814 el.un('mouseleave' ,this.onEventLeave, this);
60822 renderEvent : function(ev,ctr) {
60824 ctr = this.view.el.select('.fc-event-container',true).first();
60828 this.clearEvent(ev);
60834 var cells = ev.cells;
60835 var rows = ev.rows;
60836 this.fireEvent('eventrender', this, ev);
60838 for(var i =0; i < rows.length; i++) {
60842 cls += ' fc-event-start';
60844 if ((i+1) == rows.length) {
60845 cls += ' fc-event-end';
60848 //Roo.log(ev.data);
60849 // how many rows should it span..
60850 var cg = this.eventTmpl.append(ctr,Roo.apply({
60853 }, ev.data) , true);
60856 cg.on('mouseenter' ,this.onEventEnter, this, ev);
60857 cg.on('mouseleave' ,this.onEventLeave, this, ev);
60858 cg.on('click', this.onEventClick, this, ev);
60862 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
60863 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
60866 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
60867 cg.setWidth(ebox.right - sbox.x -2);
60871 renderEvents: function()
60873 // first make sure there is enough space..
60875 if (!this.eventTmpl) {
60876 this.eventTmpl = new Roo.Template(
60877 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
60878 '<div class="fc-event-inner">' +
60879 '<span class="fc-event-time">{time}</span>' +
60880 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
60882 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
60890 this.cells.each(function(c) {
60891 //Roo.log(c.select('.fc-day-content div',true).first());
60892 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
60895 var ctr = this.view.el.select('.fc-event-container',true).first();
60898 this.eventStore.each(function(ev){
60900 this.renderEvent(ev);
60904 this.view.layout();
60908 onEventEnter: function (e, el,event,d) {
60909 this.fireEvent('evententer', this, el, event);
60912 onEventLeave: function (e, el,event,d) {
60913 this.fireEvent('eventleave', this, el, event);
60916 onEventClick: function (e, el,event,d) {
60917 this.fireEvent('eventclick', this, el, event);
60920 onMonthChange: function () {
60924 onLoad: function () {
60926 //Roo.log('calendar onload');
60928 if(this.eventStore.getCount() > 0){
60932 this.eventStore.each(function(d){
60937 if (typeof(add.end_dt) == 'undefined') {
60938 Roo.log("Missing End time in calendar data: ");
60942 if (typeof(add.start_dt) == 'undefined') {
60943 Roo.log("Missing Start time in calendar data: ");
60947 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
60948 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
60949 add.id = add.id || d.id;
60950 add.title = add.title || '??';
60958 this.renderEvents();
60968 render : function ()
60972 if (!this.view.el.hasClass('course-timesheet')) {
60973 this.view.el.addClass('course-timesheet');
60975 if (this.tsStyle) {
60980 Roo.log(_this.grid.view.el.getWidth());
60983 this.tsStyle = Roo.util.CSS.createStyleSheet({
60984 '.course-timesheet .x-grid-row' : {
60987 '.x-grid-row td' : {
60988 'vertical-align' : 0
60990 '.course-edit-link' : {
60992 'text-overflow' : 'ellipsis',
60993 'overflow' : 'hidden',
60994 'white-space' : 'nowrap',
60995 'cursor' : 'pointer'
61000 '.de-act-sup-link' : {
61001 'color' : 'purple',
61002 'text-decoration' : 'line-through'
61006 'text-decoration' : 'line-through'
61008 '.course-timesheet .course-highlight' : {
61009 'border-top-style': 'dashed !important',
61010 'border-bottom-bottom': 'dashed !important'
61012 '.course-timesheet .course-item' : {
61013 'font-family' : 'tahoma, arial, helvetica',
61014 'font-size' : '11px',
61015 'overflow' : 'hidden',
61016 'padding-left' : '10px',
61017 'padding-right' : '10px',
61018 'padding-top' : '10px'
61026 monitorWindowResize : false,
61027 cellrenderer : function(v,x,r)
61032 xtype: 'CellSelectionModel',
61039 beforeload : function (_self, options)
61041 options.params = options.params || {};
61042 options.params._month = _this.monthField.getValue();
61043 options.params.limit = 9999;
61044 options.params['sort'] = 'when_dt';
61045 options.params['dir'] = 'ASC';
61046 this.proxy.loadResponse = this.loadResponse;
61048 //this.addColumns();
61050 load : function (_self, records, options)
61052 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
61053 // if you click on the translation.. you can edit it...
61054 var el = Roo.get(this);
61055 var id = el.dom.getAttribute('data-id');
61056 var d = el.dom.getAttribute('data-date');
61057 var t = el.dom.getAttribute('data-time');
61058 //var id = this.child('span').dom.textContent;
61061 Pman.Dialog.CourseCalendar.show({
61065 productitem_active : id ? 1 : 0
61067 _this.grid.ds.load({});
61072 _this.panel.fireEvent('resize', [ '', '' ]);
61075 loadResponse : function(o, success, response){
61076 // this is overridden on before load..
61078 Roo.log("our code?");
61079 //Roo.log(success);
61080 //Roo.log(response)
61081 delete this.activeRequest;
61083 this.fireEvent("loadexception", this, o, response);
61084 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61089 result = o.reader.read(response);
61091 Roo.log("load exception?");
61092 this.fireEvent("loadexception", this, o, response, e);
61093 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61096 Roo.log("ready...");
61097 // loop through result.records;
61098 // and set this.tdate[date] = [] << array of records..
61100 Roo.each(result.records, function(r){
61102 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61103 _this.tdata[r.data.when_dt.format('j')] = [];
61105 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61108 //Roo.log(_this.tdata);
61110 result.records = [];
61111 result.totalRecords = 6;
61113 // let's generate some duumy records for the rows.
61114 //var st = _this.dateField.getValue();
61116 // work out monday..
61117 //st = st.add(Date.DAY, -1 * st.format('w'));
61119 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61121 var firstOfMonth = date.getFirstDayOfMonth();
61122 var days = date.getDaysInMonth();
61124 var firstAdded = false;
61125 for (var i = 0; i < result.totalRecords ; i++) {
61126 //var d= st.add(Date.DAY, i);
61129 for(var w = 0 ; w < 7 ; w++){
61130 if(!firstAdded && firstOfMonth != w){
61137 var dd = (d > 0 && d < 10) ? "0"+d : d;
61138 row['weekday'+w] = String.format(
61139 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61140 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61142 date.format('Y-m-')+dd
61145 if(typeof(_this.tdata[d]) != 'undefined'){
61146 Roo.each(_this.tdata[d], function(r){
61150 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61151 if(r.parent_id*1>0){
61152 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61155 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61156 deactive = 'de-act-link';
61159 row['weekday'+w] += String.format(
61160 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61162 r.product_id_name, //1
61163 r.when_dt.format('h:ia'), //2
61173 // only do this if something added..
61175 result.records.push(_this.grid.dataSource.reader.newRow(row));
61179 // push it twice. (second one with an hour..
61183 this.fireEvent("load", this, o, o.request.arg);
61184 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61186 sortInfo : {field: 'when_dt', direction : 'ASC' },
61188 xtype: 'HttpProxy',
61191 url : baseURL + '/Roo/Shop_course.php'
61194 xtype: 'JsonReader',
61211 'name': 'parent_id',
61215 'name': 'product_id',
61219 'name': 'productitem_id',
61237 click : function (_self, e)
61239 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61240 sd.setMonth(sd.getMonth()-1);
61241 _this.monthField.setValue(sd.format('Y-m-d'));
61242 _this.grid.ds.load({});
61248 xtype: 'Separator',
61252 xtype: 'MonthField',
61255 render : function (_self)
61257 _this.monthField = _self;
61258 // _this.monthField.set today
61260 select : function (combo, date)
61262 _this.grid.ds.load({});
61265 value : (function() { return new Date(); })()
61268 xtype: 'Separator',
61274 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61284 click : function (_self, e)
61286 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61287 sd.setMonth(sd.getMonth()+1);
61288 _this.monthField.setValue(sd.format('Y-m-d'));
61289 _this.grid.ds.load({});
61302 * Ext JS Library 1.1.1
61303 * Copyright(c) 2006-2007, Ext JS, LLC.
61305 * Originally Released Under LGPL - original licence link has changed is not relivant.
61308 * <script type="text/javascript">
61312 * @class Roo.LoadMask
61313 * A simple utility class for generically masking elements while loading data. If the element being masked has
61314 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61315 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61316 * element's UpdateManager load indicator and will be destroyed after the initial load.
61318 * Create a new LoadMask
61319 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61320 * @param {Object} config The config object
61322 Roo.LoadMask = function(el, config){
61323 this.el = Roo.get(el);
61324 Roo.apply(this, config);
61326 this.store.on('beforeload', this.onBeforeLoad, this);
61327 this.store.on('load', this.onLoad, this);
61328 this.store.on('loadexception', this.onLoadException, this);
61329 this.removeMask = false;
61331 var um = this.el.getUpdateManager();
61332 um.showLoadIndicator = false; // disable the default indicator
61333 um.on('beforeupdate', this.onBeforeLoad, this);
61334 um.on('update', this.onLoad, this);
61335 um.on('failure', this.onLoad, this);
61336 this.removeMask = true;
61340 Roo.LoadMask.prototype = {
61342 * @cfg {Boolean} removeMask
61343 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61344 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61347 * @cfg {String} msg
61348 * The text to display in a centered loading message box (defaults to 'Loading...')
61350 msg : 'Loading...',
61352 * @cfg {String} msgCls
61353 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61355 msgCls : 'x-mask-loading',
61358 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61364 * Disables the mask to prevent it from being displayed
61366 disable : function(){
61367 this.disabled = true;
61371 * Enables the mask so that it can be displayed
61373 enable : function(){
61374 this.disabled = false;
61377 onLoadException : function()
61379 Roo.log(arguments);
61381 if (typeof(arguments[3]) != 'undefined') {
61382 Roo.MessageBox.alert("Error loading",arguments[3]);
61386 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61387 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61394 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61397 onLoad : function()
61399 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61403 onBeforeLoad : function(){
61404 if(!this.disabled){
61405 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61410 destroy : function(){
61412 this.store.un('beforeload', this.onBeforeLoad, this);
61413 this.store.un('load', this.onLoad, this);
61414 this.store.un('loadexception', this.onLoadException, this);
61416 var um = this.el.getUpdateManager();
61417 um.un('beforeupdate', this.onBeforeLoad, this);
61418 um.un('update', this.onLoad, this);
61419 um.un('failure', this.onLoad, this);
61424 * Ext JS Library 1.1.1
61425 * Copyright(c) 2006-2007, Ext JS, LLC.
61427 * Originally Released Under LGPL - original licence link has changed is not relivant.
61430 * <script type="text/javascript">
61435 * @class Roo.XTemplate
61436 * @extends Roo.Template
61437 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61439 var t = new Roo.XTemplate(
61440 '<select name="{name}">',
61441 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61445 // then append, applying the master template values
61448 * Supported features:
61453 {a_variable} - output encoded.
61454 {a_variable.format:("Y-m-d")} - call a method on the variable
61455 {a_variable:raw} - unencoded output
61456 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61457 {a_variable:this.method_on_template(...)} - call a method on the template object.
61462 <tpl for="a_variable or condition.."></tpl>
61463 <tpl if="a_variable or condition"></tpl>
61464 <tpl exec="some javascript"></tpl>
61465 <tpl name="named_template"></tpl> (experimental)
61467 <tpl for="."></tpl> - just iterate the property..
61468 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61472 Roo.XTemplate = function()
61474 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61481 Roo.extend(Roo.XTemplate, Roo.Template, {
61484 * The various sub templates
61489 * basic tag replacing syntax
61492 * // you can fake an object call by doing this
61496 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61499 * compile the template
61501 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61504 compile: function()
61508 s = ['<tpl>', s, '</tpl>'].join('');
61510 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61511 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61512 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61513 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61514 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61519 while(true == !!(m = s.match(re))){
61520 var forMatch = m[0].match(nameRe),
61521 ifMatch = m[0].match(ifRe),
61522 execMatch = m[0].match(execRe),
61523 namedMatch = m[0].match(namedRe),
61528 name = forMatch && forMatch[1] ? forMatch[1] : '';
61531 // if - puts fn into test..
61532 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61534 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61539 // exec - calls a function... returns empty if true is returned.
61540 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61542 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61550 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61551 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61552 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61555 var uid = namedMatch ? namedMatch[1] : id;
61559 id: namedMatch ? namedMatch[1] : id,
61566 s = s.replace(m[0], '');
61568 s = s.replace(m[0], '{xtpl'+ id + '}');
61573 for(var i = tpls.length-1; i >= 0; --i){
61574 this.compileTpl(tpls[i]);
61575 this.tpls[tpls[i].id] = tpls[i];
61577 this.master = tpls[tpls.length-1];
61581 * same as applyTemplate, except it's done to one of the subTemplates
61582 * when using named templates, you can do:
61584 * var str = pl.applySubTemplate('your-name', values);
61587 * @param {Number} id of the template
61588 * @param {Object} values to apply to template
61589 * @param {Object} parent (normaly the instance of this object)
61591 applySubTemplate : function(id, values, parent)
61595 var t = this.tpls[id];
61599 if(t.test && !t.test.call(this, values, parent)){
61603 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61604 Roo.log(e.toString());
61610 if(t.exec && t.exec.call(this, values, parent)){
61614 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61615 Roo.log(e.toString());
61620 var vs = t.target ? t.target.call(this, values, parent) : values;
61621 parent = t.target ? values : parent;
61622 if(t.target && vs instanceof Array){
61624 for(var i = 0, len = vs.length; i < len; i++){
61625 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61627 return buf.join('');
61629 return t.compiled.call(this, vs, parent);
61631 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61632 Roo.log(e.toString());
61633 Roo.log(t.compiled);
61638 compileTpl : function(tpl)
61640 var fm = Roo.util.Format;
61641 var useF = this.disableFormats !== true;
61642 var sep = Roo.isGecko ? "+" : ",";
61643 var undef = function(str) {
61644 Roo.log("Property not found :" + str);
61648 var fn = function(m, name, format, args)
61650 //Roo.log(arguments);
61651 args = args ? args.replace(/\\'/g,"'") : args;
61652 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61653 if (typeof(format) == 'undefined') {
61654 format= 'htmlEncode';
61656 if (format == 'raw' ) {
61660 if(name.substr(0, 4) == 'xtpl'){
61661 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
61664 // build an array of options to determine if value is undefined..
61666 // basically get 'xxxx.yyyy' then do
61667 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
61668 // (function () { Roo.log("Property not found"); return ''; })() :
61673 Roo.each(name.split('.'), function(st) {
61674 lookfor += (lookfor.length ? '.': '') + st;
61675 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
61678 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
61681 if(format && useF){
61683 args = args ? ',' + args : "";
61685 if(format.substr(0, 5) != "this."){
61686 format = "fm." + format + '(';
61688 format = 'this.call("'+ format.substr(5) + '", ';
61692 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
61696 // called with xxyx.yuu:(test,test)
61698 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
61700 // raw.. - :raw modifier..
61701 return "'"+ sep + udef_st + name + ")"+sep+"'";
61705 // branched to use + in gecko and [].join() in others
61707 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
61708 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
61711 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
61712 body.push(tpl.body.replace(/(\r\n|\n)/g,
61713 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
61714 body.push("'].join('');};};");
61715 body = body.join('');
61718 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
61720 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
61726 applyTemplate : function(values){
61727 return this.master.compiled.call(this, values, {});
61728 //var s = this.subs;
61731 apply : function(){
61732 return this.applyTemplate.apply(this, arguments);
61737 Roo.XTemplate.from = function(el){
61738 el = Roo.getDom(el);
61739 return new Roo.XTemplate(el.value || el.innerHTML);