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 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isIOS = /iphone|ipad/.test(ua),
67 isTouch = (function() {
69 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
70 window.addEventListener('touchstart', function __set_has_touch__ () {
72 window.removeEventListener('touchstart', __set_has_touch__);
74 return false; // no touch on chrome!?
76 document.createEvent("TouchEvent");
83 // remove css image flicker
86 document.execCommand("BackgroundImageCache", false, true);
92 * True if the browser is in strict mode
97 * True if the page is running over SSL
102 * True when the document is fully initialized and ready for action
107 * Turn on debugging output (currently only the factory uses this)
114 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117 enableGarbageCollector : true,
120 * True to automatically purge event listeners after uncaching an element (defaults to false).
121 * Note: this only happens if enableGarbageCollector is true.
124 enableListenerCollection:false,
127 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
128 * the IE insecure content warning (defaults to javascript:false).
131 SSL_SECURE_URL : "javascript:false",
134 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
135 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
140 emptyFn : function(){},
143 * Copies all the properties of config to obj if they don't already exist.
144 * @param {Object} obj The receiver of the properties
145 * @param {Object} config The source of the properties
146 * @return {Object} returns obj
148 applyIf : function(o, c){
151 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
158 * Applies event listeners to elements by selectors when the document is ready.
159 * The event name is specified with an @ suffix.
162 // add a listener for click on all anchors in element with id foo
163 '#foo a@click' : function(e, t){
167 // add the same listener to multiple selectors (separated by comma BEFORE the @)
168 '#foo a, #bar span.some-class@mouseover' : function(){
173 * @param {Object} obj The list of behaviors to apply
175 addBehaviors : function(o){
177 Roo.onReady(function(){
182 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
184 var parts = b.split('@');
185 if(parts[1]){ // for Object prototype breakers
188 cache[s] = Roo.select(s);
190 cache[s].on(parts[1], o[b]);
197 * Generates unique ids. If the element already has an id, it is unchanged
198 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
199 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
200 * @return {String} The generated Id.
202 id : function(el, prefix){
203 prefix = prefix || "roo-gen";
205 var id = prefix + (++idSeed);
206 return el ? (el.id ? el.id : (el.id = id)) : id;
211 * Extends one class with another class and optionally overrides members with the passed literal. This class
212 * also adds the function "override()" to the class that can be used to override
213 * members on an instance.
214 * @param {Object} subclass The class inheriting the functionality
215 * @param {Object} superclass The class being extended
216 * @param {Object} overrides (optional) A literal with members
221 var io = function(o){
226 return function(sb, sp, overrides){
227 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230 sb = function(){sp.apply(this, arguments);};
232 var F = function(){}, sbp, spp = sp.prototype;
234 sbp = sb.prototype = new F();
238 if(spp.constructor == Object.prototype.constructor){
243 sb.override = function(o){
247 Roo.override(sb, overrides);
253 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
255 Roo.override(MyClass, {
256 newMethod1: function(){
259 newMethod2: function(foo){
264 * @param {Object} origclass The class to override
265 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
266 * containing one or more methods.
269 override : function(origclass, overrides){
271 var p = origclass.prototype;
272 for(var method in overrides){
273 p[method] = overrides[method];
278 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
280 Roo.namespace('Company', 'Company.data');
281 Company.Widget = function() { ... }
282 Company.data.CustomStore = function(config) { ... }
284 * @param {String} namespace1
285 * @param {String} namespace2
286 * @param {String} etc
289 namespace : function(){
290 var a=arguments, o=null, i, j, d, rt;
291 for (i=0; i<a.length; ++i) {
295 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
296 for (j=1; j<d.length; ++j) {
297 o[d[j]]=o[d[j]] || {};
303 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
305 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
306 Roo.factory(conf, Roo.data);
308 * @param {String} classname
309 * @param {String} namespace (optional)
313 factory : function(c, ns)
315 // no xtype, no ns or c.xns - or forced off by c.xns
316 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
319 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
320 if (c.constructor == ns[c.xtype]) {// already created...
324 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
325 var ret = new ns[c.xtype](c);
329 c.xns = false; // prevent recursion..
333 * Logs to console if it can.
335 * @param {String|Object} string
340 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
347 * 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.
351 urlEncode : function(o){
357 var ov = o[key], k = Roo.encodeURIComponent(key);
358 var type = typeof ov;
359 if(type == 'undefined'){
361 }else if(type != "function" && type != "object"){
362 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
363 }else if(ov instanceof Array){
365 for(var i = 0, len = ov.length; i < len; i++) {
366 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
377 * Safe version of encodeURIComponent
378 * @param {String} data
382 encodeURIComponent : function (data)
385 return encodeURIComponent(data);
386 } catch(e) {} // should be an uri encode error.
388 if (data == '' || data == null){
391 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
392 function nibble_to_hex(nibble){
393 var chars = '0123456789ABCDEF';
394 return chars.charAt(nibble);
396 data = data.toString();
398 for(var i=0; i<data.length; i++){
399 var c = data.charCodeAt(i);
400 var bs = new Array();
403 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
404 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
405 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
406 bs[3] = 0x80 | (c & 0x3F);
407 }else if (c > 0x800){
409 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
410 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
411 bs[2] = 0x80 | (c & 0x3F);
414 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
415 bs[1] = 0x80 | (c & 0x3F);
420 for(var j=0; j<bs.length; j++){
422 var hex = nibble_to_hex((b & 0xF0) >>> 4)
423 + nibble_to_hex(b &0x0F);
432 * 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]}.
433 * @param {String} string
434 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
435 * @return {Object} A literal with members
437 urlDecode : function(string, overwrite){
438 if(!string || !string.length){
442 var pairs = string.split('&');
443 var pair, name, value;
444 for(var i = 0, len = pairs.length; i < len; i++){
445 pair = pairs[i].split('=');
446 name = decodeURIComponent(pair[0]);
447 value = decodeURIComponent(pair[1]);
448 if(overwrite !== true){
449 if(typeof obj[name] == "undefined"){
451 }else if(typeof obj[name] == "string"){
452 obj[name] = [obj[name]];
453 obj[name].push(value);
455 obj[name].push(value);
465 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
466 * passed array is not really an array, your function is called once with it.
467 * The supplied function is called with (Object item, Number index, Array allItems).
468 * @param {Array/NodeList/Mixed} array
469 * @param {Function} fn
470 * @param {Object} scope
472 each : function(array, fn, scope){
473 if(typeof array.length == "undefined" || typeof array == "string"){
476 for(var i = 0, len = array.length; i < len; i++){
477 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
482 combine : function(){
483 var as = arguments, l = as.length, r = [];
484 for(var i = 0; i < l; i++){
486 if(a instanceof Array){
488 }else if(a.length !== undefined && !a.substr){
489 r = r.concat(Array.prototype.slice.call(a, 0));
498 * Escapes the passed string for use in a regular expression
499 * @param {String} str
502 escapeRe : function(s) {
503 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
507 callback : function(cb, scope, args, delay){
508 if(typeof cb == "function"){
510 cb.defer(delay, scope, args || []);
512 cb.apply(scope, args || []);
518 * Return the dom node for the passed string (id), dom node, or Roo.Element
519 * @param {String/HTMLElement/Roo.Element} el
520 * @return HTMLElement
522 getDom : function(el){
526 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
530 * Shorthand for {@link Roo.ComponentMgr#get}
532 * @return Roo.Component
534 getCmp : function(id){
535 return Roo.ComponentMgr.get(id);
538 num : function(v, defaultValue){
539 if(typeof v != 'number'){
545 destroy : function(){
546 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
550 as.removeAllListeners();
554 if(typeof as.purgeListeners == 'function'){
557 if(typeof as.destroy == 'function'){
564 // inpired by a similar function in mootools library
566 * Returns the type of object that is passed in. If the object passed in is null or undefined it
567 * return false otherwise it returns one of the following values:<ul>
568 * <li><b>string</b>: If the object passed is a string</li>
569 * <li><b>number</b>: If the object passed is a number</li>
570 * <li><b>boolean</b>: If the object passed is a boolean value</li>
571 * <li><b>function</b>: If the object passed is a function reference</li>
572 * <li><b>object</b>: If the object passed is an object</li>
573 * <li><b>array</b>: If the object passed is an array</li>
574 * <li><b>regexp</b>: If the object passed is a regular expression</li>
575 * <li><b>element</b>: If the object passed is a DOM Element</li>
576 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
577 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
578 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
579 * @param {Mixed} object
583 if(o === undefined || o === null){
590 if(t == 'object' && o.nodeName) {
592 case 1: return 'element';
593 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596 if(t == 'object' || t == 'function') {
597 switch(o.constructor) {
598 case Array: return 'array';
599 case RegExp: return 'regexp';
601 if(typeof o.length == 'number' && typeof o.item == 'function') {
609 * Returns true if the passed value is null, undefined or an empty string (optional).
610 * @param {Mixed} value The value to test
611 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614 isEmpty : function(v, allowBlank){
615 return v === null || v === undefined || (!allowBlank ? v === '' : false);
623 isFirefox : isFirefox,
633 isBorderBox : isBorderBox,
635 isWindows : isWindows,
646 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
647 * you may want to set this to true.
650 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
655 * Selects a single element as a Roo Element
656 * This is about as close as you can get to jQuery's $('do crazy stuff')
657 * @param {String} selector The selector/xpath query
658 * @param {Node} root (optional) The start of the query (defaults to document).
659 * @return {Roo.Element}
661 selectNode : function(selector, root)
663 var node = Roo.DomQuery.selectNode(selector,root);
664 return node ? Roo.get(node) : new Roo.Element(false);
672 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
673 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
676 "Roo.bootstrap.dash");
679 * Ext JS Library 1.1.1
680 * Copyright(c) 2006-2007, Ext JS, LLC.
682 * Originally Released Under LGPL - original licence link has changed is not relivant.
685 * <script type="text/javascript">
689 // wrappedn so fnCleanup is not in global scope...
691 function fnCleanUp() {
692 var p = Function.prototype;
693 delete p.createSequence;
695 delete p.createDelegate;
696 delete p.createCallback;
697 delete p.createInterceptor;
699 window.detachEvent("onunload", fnCleanUp);
701 window.attachEvent("onunload", fnCleanUp);
708 * These functions are available on every Function object (any JavaScript function).
710 Roo.apply(Function.prototype, {
712 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
713 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
714 * Will create a function that is bound to those 2 args.
715 * @return {Function} The new function
717 createCallback : function(/*args...*/){
718 // make args available, in function below
719 var args = arguments;
722 return method.apply(window, args);
727 * Creates a delegate (callback) that sets the scope to obj.
728 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
729 * Will create a function that is automatically scoped to this.
730 * @param {Object} obj (optional) The object for which the scope is set
731 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733 * if a number the args are inserted at the specified position
734 * @return {Function} The new function
736 createDelegate : function(obj, args, appendArgs){
739 var callArgs = args || arguments;
740 if(appendArgs === true){
741 callArgs = Array.prototype.slice.call(arguments, 0);
742 callArgs = callArgs.concat(args);
743 }else if(typeof appendArgs == "number"){
744 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
745 var applyArgs = [appendArgs, 0].concat(args); // create method call params
746 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
748 return method.apply(obj || window, callArgs);
753 * Calls this function after the number of millseconds specified.
754 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
755 * @param {Object} obj (optional) The object for which the scope is set
756 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
757 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
758 * if a number the args are inserted at the specified position
759 * @return {Number} The timeout id that can be used with clearTimeout
761 defer : function(millis, obj, args, appendArgs){
762 var fn = this.createDelegate(obj, args, appendArgs);
764 return setTimeout(fn, millis);
770 * Create a combined function call sequence of the original function + the passed function.
771 * The resulting function returns the results of the original function.
772 * The passed fcn is called with the parameters of the original function
773 * @param {Function} fcn The function to sequence
774 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
775 * @return {Function} The new function
777 createSequence : function(fcn, scope){
778 if(typeof fcn != "function"){
783 var retval = method.apply(this || window, arguments);
784 fcn.apply(scope || this || window, arguments);
790 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
791 * The resulting function returns the results of the original function.
792 * The passed fcn is called with the parameters of the original function.
794 * @param {Function} fcn The function to call before the original
795 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
796 * @return {Function} The new function
798 createInterceptor : function(fcn, scope){
799 if(typeof fcn != "function"){
806 if(fcn.apply(scope || this || window, arguments) === false){
809 return method.apply(this || window, arguments);
815 * Ext JS Library 1.1.1
816 * Copyright(c) 2006-2007, Ext JS, LLC.
818 * Originally Released Under LGPL - original licence link has changed is not relivant.
821 * <script type="text/javascript">
824 Roo.applyIf(String, {
829 * Escapes the passed string for ' and \
830 * @param {String} string The string to escape
831 * @return {String} The escaped string
834 escape : function(string) {
835 return string.replace(/('|\\)/g, "\\$1");
839 * Pads the left side of a string with a specified character. This is especially useful
840 * for normalizing number and date strings. Example usage:
842 var s = String.leftPad('123', 5, '0');
843 // s now contains the string: '00123'
845 * @param {String} string The original string
846 * @param {Number} size The total length of the output string
847 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
848 * @return {String} The padded string
851 leftPad : function (val, size, ch) {
852 var result = new String(val);
853 if(ch === null || ch === undefined || ch === '') {
856 while (result.length < size) {
857 result = ch + result;
863 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
864 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
866 var cls = 'my-class', text = 'Some text';
867 var s = String.format('<div class="{0}">{1}</div>', cls, text);
868 // s now contains the string: '<div class="my-class">Some text</div>'
870 * @param {String} string The tokenized string to be formatted
871 * @param {String} value1 The value to replace token {0}
872 * @param {String} value2 Etc...
873 * @return {String} The formatted string
876 format : function(format){
877 var args = Array.prototype.slice.call(arguments, 1);
878 return format.replace(/\{(\d+)\}/g, function(m, i){
879 return Roo.util.Format.htmlEncode(args[i]);
885 * Utility function that allows you to easily switch a string between two alternating values. The passed value
886 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
887 * they are already different, the first value passed in is returned. Note that this method returns the new value
888 * but does not change the current string.
890 // alternate sort directions
891 sort = sort.toggle('ASC', 'DESC');
893 // instead of conditional logic:
894 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
896 * @param {String} value The value to compare to the current string
897 * @param {String} other The new value to use if the string already equals the first value passed in
898 * @return {String} The new value
901 String.prototype.toggle = function(value, other){
902 return this == value ? other : value;
905 * Ext JS Library 1.1.1
906 * Copyright(c) 2006-2007, Ext JS, LLC.
908 * Originally Released Under LGPL - original licence link has changed is not relivant.
911 * <script type="text/javascript">
917 Roo.applyIf(Number.prototype, {
919 * Checks whether or not the current number is within a desired range. If the number is already within the
920 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
921 * exceeded. Note that this method returns the constrained value but does not change the current number.
922 * @param {Number} min The minimum number in the range
923 * @param {Number} max The maximum number in the range
924 * @return {Number} The constrained value if outside the range, otherwise the current value
926 constrain : function(min, max){
927 return Math.min(Math.max(this, min), max);
931 * Ext JS Library 1.1.1
932 * Copyright(c) 2006-2007, Ext JS, LLC.
934 * Originally Released Under LGPL - original licence link has changed is not relivant.
937 * <script type="text/javascript">
942 Roo.applyIf(Array.prototype, {
945 * Checks whether or not the specified object exists in the array.
946 * @param {Object} o The object to check for
947 * @return {Number} The index of o in the array (or -1 if it is not found)
949 indexOf : function(o){
950 for (var i = 0, len = this.length; i < len; i++){
951 if(this[i] == o) { return i; }
957 * Removes the specified object from the array. If the object is not found nothing happens.
958 * @param {Object} o The object to remove
960 remove : function(o){
961 var index = this.indexOf(o);
963 this.splice(index, 1);
967 * Map (JS 1.6 compatibility)
968 * @param {Function} function to call
972 var len = this.length >>> 0;
973 if (typeof fun != "function") {
974 throw new TypeError();
976 var res = new Array(len);
977 var thisp = arguments[1];
978 for (var i = 0; i < len; i++)
981 res[i] = fun.call(thisp, this[i], i, this);
994 * Ext JS Library 1.1.1
995 * Copyright(c) 2006-2007, Ext JS, LLC.
997 * Originally Released Under LGPL - original licence link has changed is not relivant.
1000 * <script type="text/javascript">
1006 * The date parsing and format syntax is a subset of
1007 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1008 * supported will provide results equivalent to their PHP versions.
1010 * Following is the list of all currently supported formats:
1013 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1015 Format Output Description
1016 ------ ---------- --------------------------------------------------------------
1017 d 10 Day of the month, 2 digits with leading zeros
1018 D Wed A textual representation of a day, three letters
1019 j 10 Day of the month without leading zeros
1020 l Wednesday A full textual representation of the day of the week
1021 S th English ordinal day of month suffix, 2 chars (use with j)
1022 w 3 Numeric representation of the day of the week
1023 z 9 The julian date, or day of the year (0-365)
1024 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1025 F January A full textual representation of the month
1026 m 01 Numeric representation of a month, with leading zeros
1027 M Jan Month name abbreviation, three letters
1028 n 1 Numeric representation of a month, without leading zeros
1029 t 31 Number of days in the given month
1030 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1031 Y 2007 A full numeric representation of a year, 4 digits
1032 y 07 A two digit representation of a year
1033 a pm Lowercase Ante meridiem and Post meridiem
1034 A PM Uppercase Ante meridiem and Post meridiem
1035 g 3 12-hour format of an hour without leading zeros
1036 G 15 24-hour format of an hour without leading zeros
1037 h 03 12-hour format of an hour with leading zeros
1038 H 15 24-hour format of an hour with leading zeros
1039 i 05 Minutes with leading zeros
1040 s 01 Seconds, with leading zeros
1041 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1042 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1043 T CST Timezone setting of the machine running the code
1044 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1047 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1049 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1050 document.write(dt.format('Y-m-d')); //2007-01-10
1051 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1052 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
1055 * Here are some standard date/time patterns that you might find helpful. They
1056 * are not part of the source of Date.js, but to use them you can simply copy this
1057 * block of code into any script that is included after Date.js and they will also become
1058 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1061 ISO8601Long:"Y-m-d H:i:s",
1062 ISO8601Short:"Y-m-d",
1064 LongDate: "l, F d, Y",
1065 FullDateTime: "l, F d, Y g:i:s A",
1068 LongTime: "g:i:s A",
1069 SortableDateTime: "Y-m-d\\TH:i:s",
1070 UniversalSortableDateTime: "Y-m-d H:i:sO",
1077 var dt = new Date();
1078 document.write(dt.format(Date.patterns.ShortDate));
1083 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1084 * They generate precompiled functions from date formats instead of parsing and
1085 * processing the pattern every time you format a date. These functions are available
1086 * on every Date object (any javascript function).
1088 * The original article and download are here:
1089 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1096 Returns the number of milliseconds between this date and date
1097 @param {Date} date (optional) Defaults to now
1098 @return {Number} The diff in milliseconds
1099 @member Date getElapsed
1101 Date.prototype.getElapsed = function(date) {
1102 return Math.abs((date || new Date()).getTime()-this.getTime());
1104 // was in date file..
1108 Date.parseFunctions = {count:0};
1110 Date.parseRegexes = [];
1112 Date.formatFunctions = {count:0};
1115 Date.prototype.dateFormat = function(format) {
1116 if (Date.formatFunctions[format] == null) {
1117 Date.createNewFormat(format);
1119 var func = Date.formatFunctions[format];
1120 return this[func]();
1125 * Formats a date given the supplied format string
1126 * @param {String} format The format string
1127 * @return {String} The formatted date
1130 Date.prototype.format = Date.prototype.dateFormat;
1133 Date.createNewFormat = function(format) {
1134 var funcName = "format" + Date.formatFunctions.count++;
1135 Date.formatFunctions[format] = funcName;
1136 var code = "Date.prototype." + funcName + " = function(){return ";
1137 var special = false;
1139 for (var i = 0; i < format.length; ++i) {
1140 ch = format.charAt(i);
1141 if (!special && ch == "\\") {
1146 code += "'" + String.escape(ch) + "' + ";
1149 code += Date.getFormatCode(ch);
1152 /** eval:var:zzzzzzzzzzzzz */
1153 eval(code.substring(0, code.length - 3) + ";}");
1157 Date.getFormatCode = function(character) {
1158 switch (character) {
1160 return "String.leftPad(this.getDate(), 2, '0') + ";
1162 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1164 return "this.getDate() + ";
1166 return "Date.dayNames[this.getDay()] + ";
1168 return "this.getSuffix() + ";
1170 return "this.getDay() + ";
1172 return "this.getDayOfYear() + ";
1174 return "this.getWeekOfYear() + ";
1176 return "Date.monthNames[this.getMonth()] + ";
1178 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1180 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1182 return "(this.getMonth() + 1) + ";
1184 return "this.getDaysInMonth() + ";
1186 return "(this.isLeapYear() ? 1 : 0) + ";
1188 return "this.getFullYear() + ";
1190 return "('' + this.getFullYear()).substring(2, 4) + ";
1192 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1194 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1196 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1198 return "this.getHours() + ";
1200 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1202 return "String.leftPad(this.getHours(), 2, '0') + ";
1204 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1206 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1208 return "this.getGMTOffset() + ";
1210 return "this.getGMTColonOffset() + ";
1212 return "this.getTimezone() + ";
1214 return "(this.getTimezoneOffset() * -60) + ";
1216 return "'" + String.escape(character) + "' + ";
1221 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1222 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1223 * the date format that is not specified will default to the current date value for that part. Time parts can also
1224 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1225 * string or the parse operation will fail.
1228 //dt = Fri May 25 2007 (current date)
1229 var dt = new Date();
1231 //dt = Thu May 25 2006 (today's month/day in 2006)
1232 dt = Date.parseDate("2006", "Y");
1234 //dt = Sun Jan 15 2006 (all date parts specified)
1235 dt = Date.parseDate("2006-1-15", "Y-m-d");
1237 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1238 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1240 * @param {String} input The unparsed date as a string
1241 * @param {String} format The format the date is in
1242 * @return {Date} The parsed date
1245 Date.parseDate = function(input, format) {
1246 if (Date.parseFunctions[format] == null) {
1247 Date.createParser(format);
1249 var func = Date.parseFunctions[format];
1250 return Date[func](input);
1256 Date.createParser = function(format) {
1257 var funcName = "parse" + Date.parseFunctions.count++;
1258 var regexNum = Date.parseRegexes.length;
1259 var currentGroup = 1;
1260 Date.parseFunctions[format] = funcName;
1262 var code = "Date." + funcName + " = function(input){\n"
1263 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1264 + "var d = new Date();\n"
1265 + "y = d.getFullYear();\n"
1266 + "m = d.getMonth();\n"
1267 + "d = d.getDate();\n"
1268 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1269 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1270 + "if (results && results.length > 0) {";
1273 var special = false;
1275 for (var i = 0; i < format.length; ++i) {
1276 ch = format.charAt(i);
1277 if (!special && ch == "\\") {
1282 regex += String.escape(ch);
1285 var obj = Date.formatCodeToRegex(ch, currentGroup);
1286 currentGroup += obj.g;
1288 if (obj.g && obj.c) {
1294 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1295 + "{v = new Date(y, m, d, h, i, s);}\n"
1296 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1297 + "{v = new Date(y, m, d, h, i);}\n"
1298 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1299 + "{v = new Date(y, m, d, h);}\n"
1300 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1301 + "{v = new Date(y, m, d);}\n"
1302 + "else if (y >= 0 && m >= 0)\n"
1303 + "{v = new Date(y, m);}\n"
1304 + "else if (y >= 0)\n"
1305 + "{v = new Date(y);}\n"
1306 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1307 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1308 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1311 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1312 /** eval:var:zzzzzzzzzzzzz */
1317 Date.formatCodeToRegex = function(character, currentGroup) {
1318 switch (character) {
1322 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1325 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1326 s:"(\\d{1,2})"}; // day of month without leading zeroes
1329 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1330 s:"(\\d{2})"}; // day of month with leading zeroes
1334 s:"(?:" + Date.dayNames.join("|") + ")"};
1338 s:"(?:st|nd|rd|th)"};
1353 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1354 s:"(" + Date.monthNames.join("|") + ")"};
1357 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1358 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1361 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1362 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1365 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1366 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1377 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1381 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1382 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1386 c:"if (results[" + currentGroup + "] == 'am') {\n"
1387 + "if (h == 12) { h = 0; }\n"
1388 + "} else { if (h < 12) { h += 12; }}",
1392 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1393 + "if (h == 12) { h = 0; }\n"
1394 + "} else { if (h < 12) { h += 12; }}",
1399 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1400 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1404 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1405 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1408 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1412 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1417 "o = results[", currentGroup, "];\n",
1418 "var sn = o.substring(0,1);\n", // get + / - sign
1419 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1420 "var mn = o.substring(3,5) % 60;\n", // get minutes
1421 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1422 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1424 s:"([+\-]\\d{2,4})"};
1430 "o = results[", currentGroup, "];\n",
1431 "var sn = o.substring(0,1);\n",
1432 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1433 "var mn = o.substring(4,6) % 60;\n",
1434 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1435 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1441 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1444 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1445 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1446 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1450 s:String.escape(character)};
1455 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1456 * @return {String} The abbreviated timezone name (e.g. 'CST')
1458 Date.prototype.getTimezone = function() {
1459 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1463 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1464 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1466 Date.prototype.getGMTOffset = function() {
1467 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1468 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1473 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1474 * @return {String} 2-characters representing hours and 2-characters representing minutes
1475 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1477 Date.prototype.getGMTColonOffset = function() {
1478 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1479 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1481 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1485 * Get the numeric day number of the year, adjusted for leap year.
1486 * @return {Number} 0 through 364 (365 in leap years)
1488 Date.prototype.getDayOfYear = function() {
1490 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1491 for (var i = 0; i < this.getMonth(); ++i) {
1492 num += Date.daysInMonth[i];
1494 return num + this.getDate() - 1;
1498 * Get the string representation of the numeric week number of the year
1499 * (equivalent to the format specifier 'W').
1500 * @return {String} '00' through '52'
1502 Date.prototype.getWeekOfYear = function() {
1503 // Skip to Thursday of this week
1504 var now = this.getDayOfYear() + (4 - this.getDay());
1505 // Find the first Thursday of the year
1506 var jan1 = new Date(this.getFullYear(), 0, 1);
1507 var then = (7 - jan1.getDay() + 4);
1508 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1512 * Whether or not the current date is in a leap year.
1513 * @return {Boolean} True if the current date is in a leap year, else false
1515 Date.prototype.isLeapYear = function() {
1516 var year = this.getFullYear();
1517 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1521 * Get the first day of the current month, adjusted for leap year. The returned value
1522 * is the numeric day index within the week (0-6) which can be used in conjunction with
1523 * the {@link #monthNames} array to retrieve the textual day name.
1526 var dt = new Date('1/10/2007');
1527 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1529 * @return {Number} The day number (0-6)
1531 Date.prototype.getFirstDayOfMonth = function() {
1532 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1533 return (day < 0) ? (day + 7) : day;
1537 * Get the last day of the current month, adjusted for leap year. The returned value
1538 * is the numeric day index within the week (0-6) which can be used in conjunction with
1539 * the {@link #monthNames} array to retrieve the textual day name.
1542 var dt = new Date('1/10/2007');
1543 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1545 * @return {Number} The day number (0-6)
1547 Date.prototype.getLastDayOfMonth = function() {
1548 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1549 return (day < 0) ? (day + 7) : day;
1554 * Get the first date of this date's month
1557 Date.prototype.getFirstDateOfMonth = function() {
1558 return new Date(this.getFullYear(), this.getMonth(), 1);
1562 * Get the last date of this date's month
1565 Date.prototype.getLastDateOfMonth = function() {
1566 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1569 * Get the number of days in the current month, adjusted for leap year.
1570 * @return {Number} The number of days in the month
1572 Date.prototype.getDaysInMonth = function() {
1573 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1574 return Date.daysInMonth[this.getMonth()];
1578 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1579 * @return {String} 'st, 'nd', 'rd' or 'th'
1581 Date.prototype.getSuffix = function() {
1582 switch (this.getDate()) {
1599 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1602 * An array of textual month names.
1603 * Override these values for international dates, for example...
1604 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1623 * An array of textual day names.
1624 * Override these values for international dates, for example...
1625 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1641 Date.monthNumbers = {
1656 * Creates and returns a new Date instance with the exact same date value as the called instance.
1657 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1658 * variable will also be changed. When the intention is to create a new variable that will not
1659 * modify the original instance, you should create a clone.
1661 * Example of correctly cloning a date:
1664 var orig = new Date('10/1/2006');
1667 document.write(orig); //returns 'Thu Oct 05 2006'!
1670 var orig = new Date('10/1/2006');
1671 var copy = orig.clone();
1673 document.write(orig); //returns 'Thu Oct 01 2006'
1675 * @return {Date} The new Date instance
1677 Date.prototype.clone = function() {
1678 return new Date(this.getTime());
1682 * Clears any time information from this date
1683 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1684 @return {Date} this or the clone
1686 Date.prototype.clearTime = function(clone){
1688 return this.clone().clearTime();
1693 this.setMilliseconds(0);
1698 // safari setMonth is broken -- check that this is only donw once...
1699 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1700 Date.brokenSetMonth = Date.prototype.setMonth;
1701 Date.prototype.setMonth = function(num){
1703 var n = Math.ceil(-num);
1704 var back_year = Math.ceil(n/12);
1705 var month = (n % 12) ? 12 - n % 12 : 0 ;
1706 this.setFullYear(this.getFullYear() - back_year);
1707 return Date.brokenSetMonth.call(this, month);
1709 return Date.brokenSetMonth.apply(this, arguments);
1714 /** Date interval constant
1718 /** Date interval constant
1722 /** Date interval constant
1726 /** Date interval constant
1730 /** Date interval constant
1734 /** Date interval constant
1738 /** Date interval constant
1744 * Provides a convenient method of performing basic date arithmetic. This method
1745 * does not modify the Date instance being called - it creates and returns
1746 * a new Date instance containing the resulting date value.
1751 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1752 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1754 //Negative values will subtract correctly:
1755 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1756 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1758 //You can even chain several calls together in one line!
1759 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1760 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1763 * @param {String} interval A valid date interval enum value
1764 * @param {Number} value The amount to add to the current date
1765 * @return {Date} The new Date instance
1767 Date.prototype.add = function(interval, value){
1768 var d = this.clone();
1769 if (!interval || value === 0) { return d; }
1770 switch(interval.toLowerCase()){
1772 d.setMilliseconds(this.getMilliseconds() + value);
1775 d.setSeconds(this.getSeconds() + value);
1778 d.setMinutes(this.getMinutes() + value);
1781 d.setHours(this.getHours() + value);
1784 d.setDate(this.getDate() + value);
1787 var day = this.getDate();
1789 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1792 d.setMonth(this.getMonth() + value);
1795 d.setFullYear(this.getFullYear() + value);
1802 * Ext JS Library 1.1.1
1803 * Copyright(c) 2006-2007, Ext JS, LLC.
1805 * Originally Released Under LGPL - original licence link has changed is not relivant.
1808 * <script type="text/javascript">
1812 * @class Roo.lib.Dom
1815 * Dom utils (from YIU afaik)
1820 * Get the view width
1821 * @param {Boolean} full True will get the full document, otherwise it's the view width
1822 * @return {Number} The width
1825 getViewWidth : function(full) {
1826 return full ? this.getDocumentWidth() : this.getViewportWidth();
1829 * Get the view height
1830 * @param {Boolean} full True will get the full document, otherwise it's the view height
1831 * @return {Number} The height
1833 getViewHeight : function(full) {
1834 return full ? this.getDocumentHeight() : this.getViewportHeight();
1837 getDocumentHeight: function() {
1838 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1839 return Math.max(scrollHeight, this.getViewportHeight());
1842 getDocumentWidth: function() {
1843 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1844 return Math.max(scrollWidth, this.getViewportWidth());
1847 getViewportHeight: function() {
1848 var height = self.innerHeight;
1849 var mode = document.compatMode;
1851 if ((mode || Roo.isIE) && !Roo.isOpera) {
1852 height = (mode == "CSS1Compat") ?
1853 document.documentElement.clientHeight :
1854 document.body.clientHeight;
1860 getViewportWidth: function() {
1861 var width = self.innerWidth;
1862 var mode = document.compatMode;
1864 if (mode || Roo.isIE) {
1865 width = (mode == "CSS1Compat") ?
1866 document.documentElement.clientWidth :
1867 document.body.clientWidth;
1872 isAncestor : function(p, c) {
1879 if (p.contains && !Roo.isSafari) {
1880 return p.contains(c);
1881 } else if (p.compareDocumentPosition) {
1882 return !!(p.compareDocumentPosition(c) & 16);
1884 var parent = c.parentNode;
1889 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1892 parent = parent.parentNode;
1898 getRegion : function(el) {
1899 return Roo.lib.Region.getRegion(el);
1902 getY : function(el) {
1903 return this.getXY(el)[1];
1906 getX : function(el) {
1907 return this.getXY(el)[0];
1910 getXY : function(el) {
1911 var p, pe, b, scroll, bd = document.body;
1912 el = Roo.getDom(el);
1913 var fly = Roo.lib.AnimBase.fly;
1914 if (el.getBoundingClientRect) {
1915 b = el.getBoundingClientRect();
1916 scroll = fly(document).getScroll();
1917 return [b.left + scroll.left, b.top + scroll.top];
1923 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1930 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1937 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1938 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1945 if (p != el && pe.getStyle('overflow') != 'visible') {
1953 if (Roo.isSafari && hasAbsolute) {
1958 if (Roo.isGecko && !hasAbsolute) {
1960 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1961 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1965 while (p && p != bd) {
1966 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1978 setXY : function(el, xy) {
1979 el = Roo.fly(el, '_setXY');
1981 var pts = el.translatePoints(xy);
1982 if (xy[0] !== false) {
1983 el.dom.style.left = pts.left + "px";
1985 if (xy[1] !== false) {
1986 el.dom.style.top = pts.top + "px";
1990 setX : function(el, x) {
1991 this.setXY(el, [x, false]);
1994 setY : function(el, y) {
1995 this.setXY(el, [false, y]);
1999 * Portions of this file are based on pieces of Yahoo User Interface Library
2000 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2001 * YUI licensed under the BSD License:
2002 * http://developer.yahoo.net/yui/license.txt
2003 * <script type="text/javascript">
2007 Roo.lib.Event = function() {
2008 var loadComplete = false;
2010 var unloadListeners = [];
2012 var onAvailStack = [];
2014 var lastError = null;
2027 startInterval: function() {
2028 if (!this._interval) {
2030 var callback = function() {
2031 self._tryPreloadAttach();
2033 this._interval = setInterval(callback, this.POLL_INTERVAL);
2038 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2039 onAvailStack.push({ id: p_id,
2042 override: p_override,
2043 checkReady: false });
2045 retryCount = this.POLL_RETRYS;
2046 this.startInterval();
2050 addListener: function(el, eventName, fn) {
2051 el = Roo.getDom(el);
2056 if ("unload" == eventName) {
2057 unloadListeners[unloadListeners.length] =
2058 [el, eventName, fn];
2062 var wrappedFn = function(e) {
2063 return fn(Roo.lib.Event.getEvent(e));
2066 var li = [el, eventName, fn, wrappedFn];
2068 var index = listeners.length;
2069 listeners[index] = li;
2071 this.doAdd(el, eventName, wrappedFn, false);
2077 removeListener: function(el, eventName, fn) {
2080 el = Roo.getDom(el);
2083 return this.purgeElement(el, false, eventName);
2087 if ("unload" == eventName) {
2089 for (i = 0,len = unloadListeners.length; i < len; i++) {
2090 var li = unloadListeners[i];
2093 li[1] == eventName &&
2095 unloadListeners.splice(i, 1);
2103 var cacheItem = null;
2106 var index = arguments[3];
2108 if ("undefined" == typeof index) {
2109 index = this._getCacheIndex(el, eventName, fn);
2113 cacheItem = listeners[index];
2116 if (!el || !cacheItem) {
2120 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2122 delete listeners[index][this.WFN];
2123 delete listeners[index][this.FN];
2124 listeners.splice(index, 1);
2131 getTarget: function(ev, resolveTextNode) {
2132 ev = ev.browserEvent || ev;
2133 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2134 var t = ev.target || ev.srcElement;
2135 return this.resolveTextNode(t);
2139 resolveTextNode: function(node) {
2140 if (Roo.isSafari && node && 3 == node.nodeType) {
2141 return node.parentNode;
2148 getPageX: function(ev) {
2149 ev = ev.browserEvent || ev;
2150 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 if (!x && 0 !== x) {
2153 x = ev.clientX || 0;
2156 x += this.getScroll()[1];
2164 getPageY: function(ev) {
2165 ev = ev.browserEvent || ev;
2166 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2168 if (!y && 0 !== y) {
2169 y = ev.clientY || 0;
2172 y += this.getScroll()[0];
2181 getXY: function(ev) {
2182 ev = ev.browserEvent || ev;
2183 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2184 return [this.getPageX(ev), this.getPageY(ev)];
2188 getRelatedTarget: function(ev) {
2189 ev = ev.browserEvent || ev;
2190 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2191 var t = ev.relatedTarget;
2193 if (ev.type == "mouseout") {
2195 } else if (ev.type == "mouseover") {
2200 return this.resolveTextNode(t);
2204 getTime: function(ev) {
2205 ev = ev.browserEvent || ev;
2206 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2208 var t = new Date().getTime();
2212 this.lastError = ex;
2221 stopEvent: function(ev) {
2222 this.stopPropagation(ev);
2223 this.preventDefault(ev);
2227 stopPropagation: function(ev) {
2228 ev = ev.browserEvent || ev;
2229 if (ev.stopPropagation) {
2230 ev.stopPropagation();
2232 ev.cancelBubble = true;
2237 preventDefault: function(ev) {
2238 ev = ev.browserEvent || ev;
2239 if(ev.preventDefault) {
2240 ev.preventDefault();
2242 ev.returnValue = false;
2247 getEvent: function(e) {
2248 var ev = e || window.event;
2250 var c = this.getEvent.caller;
2252 ev = c.arguments[0];
2253 if (ev && Event == ev.constructor) {
2263 getCharCode: function(ev) {
2264 ev = ev.browserEvent || ev;
2265 return ev.charCode || ev.keyCode || 0;
2269 _getCacheIndex: function(el, eventName, fn) {
2270 for (var i = 0,len = listeners.length; i < len; ++i) {
2271 var li = listeners[i];
2273 li[this.FN] == fn &&
2274 li[this.EL] == el &&
2275 li[this.TYPE] == eventName) {
2287 getEl: function(id) {
2288 return document.getElementById(id);
2292 clearCache: function() {
2296 _load: function(e) {
2297 loadComplete = true;
2298 var EU = Roo.lib.Event;
2302 EU.doRemove(window, "load", EU._load);
2307 _tryPreloadAttach: function() {
2316 var tryAgain = !loadComplete;
2318 tryAgain = (retryCount > 0);
2323 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2324 var item = onAvailStack[i];
2326 var el = this.getEl(item.id);
2329 if (!item.checkReady ||
2332 (document && document.body)) {
2335 if (item.override) {
2336 if (item.override === true) {
2339 scope = item.override;
2342 item.fn.call(scope, item.obj);
2343 onAvailStack[i] = null;
2346 notAvail.push(item);
2351 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2355 this.startInterval();
2357 clearInterval(this._interval);
2358 this._interval = null;
2361 this.locked = false;
2368 purgeElement: function(el, recurse, eventName) {
2369 var elListeners = this.getListeners(el, eventName);
2371 for (var i = 0,len = elListeners.length; i < len; ++i) {
2372 var l = elListeners[i];
2373 this.removeListener(el, l.type, l.fn);
2377 if (recurse && el && el.childNodes) {
2378 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2379 this.purgeElement(el.childNodes[i], recurse, eventName);
2385 getListeners: function(el, eventName) {
2386 var results = [], searchLists;
2388 searchLists = [listeners, unloadListeners];
2389 } else if (eventName == "unload") {
2390 searchLists = [unloadListeners];
2392 searchLists = [listeners];
2395 for (var j = 0; j < searchLists.length; ++j) {
2396 var searchList = searchLists[j];
2397 if (searchList && searchList.length > 0) {
2398 for (var i = 0,len = searchList.length; i < len; ++i) {
2399 var l = searchList[i];
2400 if (l && l[this.EL] === el &&
2401 (!eventName || eventName === l[this.TYPE])) {
2406 adjust: l[this.ADJ_SCOPE],
2414 return (results.length) ? results : null;
2418 _unload: function(e) {
2420 var EU = Roo.lib.Event, i, j, l, len, index;
2422 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2423 l = unloadListeners[i];
2426 if (l[EU.ADJ_SCOPE]) {
2427 if (l[EU.ADJ_SCOPE] === true) {
2430 scope = l[EU.ADJ_SCOPE];
2433 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2434 unloadListeners[i] = null;
2440 unloadListeners = null;
2442 if (listeners && listeners.length > 0) {
2443 j = listeners.length;
2446 l = listeners[index];
2448 EU.removeListener(l[EU.EL], l[EU.TYPE],
2458 EU.doRemove(window, "unload", EU._unload);
2463 getScroll: function() {
2464 var dd = document.documentElement, db = document.body;
2465 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2466 return [dd.scrollTop, dd.scrollLeft];
2468 return [db.scrollTop, db.scrollLeft];
2475 doAdd: function () {
2476 if (window.addEventListener) {
2477 return function(el, eventName, fn, capture) {
2478 el.addEventListener(eventName, fn, (capture));
2480 } else if (window.attachEvent) {
2481 return function(el, eventName, fn, capture) {
2482 el.attachEvent("on" + eventName, fn);
2491 doRemove: function() {
2492 if (window.removeEventListener) {
2493 return function (el, eventName, fn, capture) {
2494 el.removeEventListener(eventName, fn, (capture));
2496 } else if (window.detachEvent) {
2497 return function (el, eventName, fn) {
2498 el.detachEvent("on" + eventName, fn);
2510 var E = Roo.lib.Event;
2511 E.on = E.addListener;
2512 E.un = E.removeListener;
2514 if (document && document.body) {
2517 E.doAdd(window, "load", E._load);
2519 E.doAdd(window, "unload", E._unload);
2520 E._tryPreloadAttach();
2524 * Portions of this file are based on pieces of Yahoo User Interface Library
2525 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2526 * YUI licensed under the BSD License:
2527 * http://developer.yahoo.net/yui/license.txt
2528 * <script type="text/javascript">
2534 * @class Roo.lib.Ajax
2541 request : function(method, uri, cb, data, options) {
2543 var hs = options.headers;
2546 if(hs.hasOwnProperty(h)){
2547 this.initHeader(h, hs[h], false);
2551 if(options.xmlData){
2552 this.initHeader('Content-Type', 'text/xml', false);
2554 data = options.xmlData;
2558 return this.asyncRequest(method, uri, cb, data);
2561 serializeForm : function(form) {
2562 if(typeof form == 'string') {
2563 form = (document.getElementById(form) || document.forms[form]);
2566 var el, name, val, disabled, data = '', hasSubmit = false;
2567 for (var i = 0; i < form.elements.length; i++) {
2568 el = form.elements[i];
2569 disabled = form.elements[i].disabled;
2570 name = form.elements[i].name;
2571 val = form.elements[i].value;
2573 if (!disabled && name){
2577 case 'select-multiple':
2578 for (var j = 0; j < el.options.length; j++) {
2579 if (el.options[j].selected) {
2581 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2584 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2592 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2605 if(hasSubmit == false) {
2606 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2611 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2616 data = data.substr(0, data.length - 1);
2624 useDefaultHeader:true,
2626 defaultPostHeader:'application/x-www-form-urlencoded',
2628 useDefaultXhrHeader:true,
2630 defaultXhrHeader:'XMLHttpRequest',
2632 hasDefaultHeaders:true,
2644 setProgId:function(id)
2646 this.activeX.unshift(id);
2649 setDefaultPostHeader:function(b)
2651 this.useDefaultHeader = b;
2654 setDefaultXhrHeader:function(b)
2656 this.useDefaultXhrHeader = b;
2659 setPollingInterval:function(i)
2661 if (typeof i == 'number' && isFinite(i)) {
2662 this.pollInterval = i;
2666 createXhrObject:function(transactionId)
2672 http = new XMLHttpRequest();
2674 obj = { conn:http, tId:transactionId };
2678 for (var i = 0; i < this.activeX.length; ++i) {
2682 http = new ActiveXObject(this.activeX[i]);
2684 obj = { conn:http, tId:transactionId };
2697 getConnectionObject:function()
2700 var tId = this.transactionId;
2704 o = this.createXhrObject(tId);
2706 this.transactionId++;
2717 asyncRequest:function(method, uri, callback, postData)
2719 var o = this.getConnectionObject();
2725 o.conn.open(method, uri, true);
2727 if (this.useDefaultXhrHeader) {
2728 if (!this.defaultHeaders['X-Requested-With']) {
2729 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2733 if(postData && this.useDefaultHeader){
2734 this.initHeader('Content-Type', this.defaultPostHeader);
2737 if (this.hasDefaultHeaders || this.hasHeaders) {
2741 this.handleReadyState(o, callback);
2742 o.conn.send(postData || null);
2748 handleReadyState:function(o, callback)
2752 if (callback && callback.timeout) {
2754 this.timeout[o.tId] = window.setTimeout(function() {
2755 oConn.abort(o, callback, true);
2756 }, callback.timeout);
2759 this.poll[o.tId] = window.setInterval(
2761 if (o.conn && o.conn.readyState == 4) {
2762 window.clearInterval(oConn.poll[o.tId]);
2763 delete oConn.poll[o.tId];
2765 if(callback && callback.timeout) {
2766 window.clearTimeout(oConn.timeout[o.tId]);
2767 delete oConn.timeout[o.tId];
2770 oConn.handleTransactionResponse(o, callback);
2773 , this.pollInterval);
2776 handleTransactionResponse:function(o, callback, isAbort)
2780 this.releaseObject(o);
2784 var httpStatus, responseObject;
2788 if (o.conn.status !== undefined && o.conn.status != 0) {
2789 httpStatus = o.conn.status;
2801 if (httpStatus >= 200 && httpStatus < 300) {
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.success) {
2804 if (!callback.scope) {
2805 callback.success(responseObject);
2810 callback.success.apply(callback.scope, [responseObject]);
2815 switch (httpStatus) {
2823 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2824 if (callback.failure) {
2825 if (!callback.scope) {
2826 callback.failure(responseObject);
2829 callback.failure.apply(callback.scope, [responseObject]);
2834 responseObject = this.createResponseObject(o, callback.argument);
2835 if (callback.failure) {
2836 if (!callback.scope) {
2837 callback.failure(responseObject);
2840 callback.failure.apply(callback.scope, [responseObject]);
2846 this.releaseObject(o);
2847 responseObject = null;
2850 createResponseObject:function(o, callbackArg)
2857 var headerStr = o.conn.getAllResponseHeaders();
2858 var header = headerStr.split('\n');
2859 for (var i = 0; i < header.length; i++) {
2860 var delimitPos = header[i].indexOf(':');
2861 if (delimitPos != -1) {
2862 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2870 obj.status = o.conn.status;
2871 obj.statusText = o.conn.statusText;
2872 obj.getResponseHeader = headerObj;
2873 obj.getAllResponseHeaders = headerStr;
2874 obj.responseText = o.conn.responseText;
2875 obj.responseXML = o.conn.responseXML;
2877 if (typeof callbackArg !== undefined) {
2878 obj.argument = callbackArg;
2884 createExceptionObject:function(tId, callbackArg, isAbort)
2887 var COMM_ERROR = 'communication failure';
2888 var ABORT_CODE = -1;
2889 var ABORT_ERROR = 'transaction aborted';
2895 obj.status = ABORT_CODE;
2896 obj.statusText = ABORT_ERROR;
2899 obj.status = COMM_CODE;
2900 obj.statusText = COMM_ERROR;
2904 obj.argument = callbackArg;
2910 initHeader:function(label, value, isDefault)
2912 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2914 if (headerObj[label] === undefined) {
2915 headerObj[label] = value;
2920 headerObj[label] = value + "," + headerObj[label];
2924 this.hasDefaultHeaders = true;
2927 this.hasHeaders = true;
2932 setHeader:function(o)
2934 if (this.hasDefaultHeaders) {
2935 for (var prop in this.defaultHeaders) {
2936 if (this.defaultHeaders.hasOwnProperty(prop)) {
2937 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2942 if (this.hasHeaders) {
2943 for (var prop in this.headers) {
2944 if (this.headers.hasOwnProperty(prop)) {
2945 o.conn.setRequestHeader(prop, this.headers[prop]);
2949 this.hasHeaders = false;
2953 resetDefaultHeaders:function() {
2954 delete this.defaultHeaders;
2955 this.defaultHeaders = {};
2956 this.hasDefaultHeaders = false;
2959 abort:function(o, callback, isTimeout)
2961 if(this.isCallInProgress(o)) {
2963 window.clearInterval(this.poll[o.tId]);
2964 delete this.poll[o.tId];
2966 delete this.timeout[o.tId];
2969 this.handleTransactionResponse(o, callback, true);
2979 isCallInProgress:function(o)
2982 return o.conn.readyState != 4 && o.conn.readyState != 0;
2991 releaseObject:function(o)
3000 'MSXML2.XMLHTTP.3.0',
3008 * Portions of this file are based on pieces of Yahoo User Interface Library
3009 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010 * YUI licensed under the BSD License:
3011 * http://developer.yahoo.net/yui/license.txt
3012 * <script type="text/javascript">
3016 Roo.lib.Region = function(t, r, b, l) {
3026 Roo.lib.Region.prototype = {
3027 contains : function(region) {
3028 return ( region.left >= this.left &&
3029 region.right <= this.right &&
3030 region.top >= this.top &&
3031 region.bottom <= this.bottom );
3035 getArea : function() {
3036 return ( (this.bottom - this.top) * (this.right - this.left) );
3039 intersect : function(region) {
3040 var t = Math.max(this.top, region.top);
3041 var r = Math.min(this.right, region.right);
3042 var b = Math.min(this.bottom, region.bottom);
3043 var l = Math.max(this.left, region.left);
3045 if (b >= t && r >= l) {
3046 return new Roo.lib.Region(t, r, b, l);
3051 union : function(region) {
3052 var t = Math.min(this.top, region.top);
3053 var r = Math.max(this.right, region.right);
3054 var b = Math.max(this.bottom, region.bottom);
3055 var l = Math.min(this.left, region.left);
3057 return new Roo.lib.Region(t, r, b, l);
3060 adjust : function(t, l, b, r) {
3069 Roo.lib.Region.getRegion = function(el) {
3070 var p = Roo.lib.Dom.getXY(el);
3073 var r = p[0] + el.offsetWidth;
3074 var b = p[1] + el.offsetHeight;
3077 return new Roo.lib.Region(t, r, b, l);
3080 * Portions of this file are based on pieces of Yahoo User Interface Library
3081 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3082 * YUI licensed under the BSD License:
3083 * http://developer.yahoo.net/yui/license.txt
3084 * <script type="text/javascript">
3087 //@@dep Roo.lib.Region
3090 Roo.lib.Point = function(x, y) {
3091 if (x instanceof Array) {
3095 this.x = this.right = this.left = this[0] = x;
3096 this.y = this.top = this.bottom = this[1] = y;
3099 Roo.lib.Point.prototype = new Roo.lib.Region();
3101 * Portions of this file are based on pieces of Yahoo User Interface Library
3102 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3103 * YUI licensed under the BSD License:
3104 * http://developer.yahoo.net/yui/license.txt
3105 * <script type="text/javascript">
3112 scroll : function(el, args, duration, easing, cb, scope) {
3113 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3116 motion : function(el, args, duration, easing, cb, scope) {
3117 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3120 color : function(el, args, duration, easing, cb, scope) {
3121 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3124 run : function(el, args, duration, easing, cb, scope, type) {
3125 type = type || Roo.lib.AnimBase;
3126 if (typeof easing == "string") {
3127 easing = Roo.lib.Easing[easing];
3129 var anim = new type(el, args, duration, easing);
3130 anim.animateX(function() {
3131 Roo.callback(cb, scope);
3137 * Portions of this file are based on pieces of Yahoo User Interface Library
3138 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139 * YUI licensed under the BSD License:
3140 * http://developer.yahoo.net/yui/license.txt
3141 * <script type="text/javascript">
3149 if (!libFlyweight) {
3150 libFlyweight = new Roo.Element.Flyweight();
3152 libFlyweight.dom = el;
3153 return libFlyweight;
3156 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3160 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3162 this.init(el, attributes, duration, method);
3166 Roo.lib.AnimBase.fly = fly;
3170 Roo.lib.AnimBase.prototype = {
3172 toString: function() {
3173 var el = this.getEl();
3174 var id = el.id || el.tagName;
3175 return ("Anim " + id);
3179 noNegatives: /width|height|opacity|padding/i,
3180 offsetAttribute: /^((width|height)|(top|left))$/,
3181 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3182 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3186 doMethod: function(attr, start, end) {
3187 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3191 setAttribute: function(attr, val, unit) {
3192 if (this.patterns.noNegatives.test(attr)) {
3193 val = (val > 0) ? val : 0;
3196 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3200 getAttribute: function(attr) {
3201 var el = this.getEl();
3202 var val = fly(el).getStyle(attr);
3204 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3205 return parseFloat(val);
3208 var a = this.patterns.offsetAttribute.exec(attr) || [];
3209 var pos = !!( a[3] );
3210 var box = !!( a[2] );
3213 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3214 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3223 getDefaultUnit: function(attr) {
3224 if (this.patterns.defaultUnit.test(attr)) {
3231 animateX : function(callback, scope) {
3232 var f = function() {
3233 this.onComplete.removeListener(f);
3234 if (typeof callback == "function") {
3235 callback.call(scope || this, this);
3238 this.onComplete.addListener(f, this);
3243 setRuntimeAttribute: function(attr) {
3246 var attributes = this.attributes;
3248 this.runtimeAttributes[attr] = {};
3250 var isset = function(prop) {
3251 return (typeof prop !== 'undefined');
3254 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3258 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3261 if (isset(attributes[attr]['to'])) {
3262 end = attributes[attr]['to'];
3263 } else if (isset(attributes[attr]['by'])) {
3264 if (start.constructor == Array) {
3266 for (var i = 0, len = start.length; i < len; ++i) {
3267 end[i] = start[i] + attributes[attr]['by'][i];
3270 end = start + attributes[attr]['by'];
3274 this.runtimeAttributes[attr].start = start;
3275 this.runtimeAttributes[attr].end = end;
3278 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3282 init: function(el, attributes, duration, method) {
3284 var isAnimated = false;
3287 var startTime = null;
3290 var actualFrames = 0;
3293 el = Roo.getDom(el);
3296 this.attributes = attributes || {};
3299 this.duration = duration || 1;
3302 this.method = method || Roo.lib.Easing.easeNone;
3305 this.useSeconds = true;
3308 this.currentFrame = 0;
3311 this.totalFrames = Roo.lib.AnimMgr.fps;
3314 this.getEl = function() {
3319 this.isAnimated = function() {
3324 this.getStartTime = function() {
3328 this.runtimeAttributes = {};
3331 this.animate = function() {
3332 if (this.isAnimated()) {
3336 this.currentFrame = 0;
3338 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3340 Roo.lib.AnimMgr.registerElement(this);
3344 this.stop = function(finish) {
3346 this.currentFrame = this.totalFrames;
3347 this._onTween.fire();
3349 Roo.lib.AnimMgr.stop(this);
3352 var onStart = function() {
3353 this.onStart.fire();
3355 this.runtimeAttributes = {};
3356 for (var attr in this.attributes) {
3357 this.setRuntimeAttribute(attr);
3362 startTime = new Date();
3366 var onTween = function() {
3368 duration: new Date() - this.getStartTime(),
3369 currentFrame: this.currentFrame
3372 data.toString = function() {
3374 'duration: ' + data.duration +
3375 ', currentFrame: ' + data.currentFrame
3379 this.onTween.fire(data);
3381 var runtimeAttributes = this.runtimeAttributes;
3383 for (var attr in runtimeAttributes) {
3384 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3390 var onComplete = function() {
3391 var actual_duration = (new Date() - startTime) / 1000 ;
3394 duration: actual_duration,
3395 frames: actualFrames,
3396 fps: actualFrames / actual_duration
3399 data.toString = function() {
3401 'duration: ' + data.duration +
3402 ', frames: ' + data.frames +
3403 ', fps: ' + data.fps
3409 this.onComplete.fire(data);
3413 this._onStart = new Roo.util.Event(this);
3414 this.onStart = new Roo.util.Event(this);
3415 this.onTween = new Roo.util.Event(this);
3416 this._onTween = new Roo.util.Event(this);
3417 this.onComplete = new Roo.util.Event(this);
3418 this._onComplete = new Roo.util.Event(this);
3419 this._onStart.addListener(onStart);
3420 this._onTween.addListener(onTween);
3421 this._onComplete.addListener(onComplete);
3426 * Portions of this file are based on pieces of Yahoo User Interface Library
3427 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3428 * YUI licensed under the BSD License:
3429 * http://developer.yahoo.net/yui/license.txt
3430 * <script type="text/javascript">
3434 Roo.lib.AnimMgr = new function() {
3451 this.registerElement = function(tween) {
3452 queue[queue.length] = tween;
3454 tween._onStart.fire();
3459 this.unRegister = function(tween, index) {
3460 tween._onComplete.fire();
3461 index = index || getIndex(tween);
3463 queue.splice(index, 1);
3467 if (tweenCount <= 0) {
3473 this.start = function() {
3474 if (thread === null) {
3475 thread = setInterval(this.run, this.delay);
3480 this.stop = function(tween) {
3482 clearInterval(thread);
3484 for (var i = 0, len = queue.length; i < len; ++i) {
3485 if (queue[0].isAnimated()) {
3486 this.unRegister(queue[0], 0);
3495 this.unRegister(tween);
3500 this.run = function() {
3501 for (var i = 0, len = queue.length; i < len; ++i) {
3502 var tween = queue[i];
3503 if (!tween || !tween.isAnimated()) {
3507 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3509 tween.currentFrame += 1;
3511 if (tween.useSeconds) {
3512 correctFrame(tween);
3514 tween._onTween.fire();
3517 Roo.lib.AnimMgr.stop(tween, i);
3522 var getIndex = function(anim) {
3523 for (var i = 0, len = queue.length; i < len; ++i) {
3524 if (queue[i] == anim) {
3532 var correctFrame = function(tween) {
3533 var frames = tween.totalFrames;
3534 var frame = tween.currentFrame;
3535 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3536 var elapsed = (new Date() - tween.getStartTime());
3539 if (elapsed < tween.duration * 1000) {
3540 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3542 tweak = frames - (frame + 1);
3544 if (tweak > 0 && isFinite(tweak)) {
3545 if (tween.currentFrame + tweak >= frames) {
3546 tweak = frames - (frame + 1);
3549 tween.currentFrame += tweak;
3555 * Portions of this file are based on pieces of Yahoo User Interface Library
3556 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557 * YUI licensed under the BSD License:
3558 * http://developer.yahoo.net/yui/license.txt
3559 * <script type="text/javascript">
3562 Roo.lib.Bezier = new function() {
3564 this.getPosition = function(points, t) {
3565 var n = points.length;
3568 for (var i = 0; i < n; ++i) {
3569 tmp[i] = [points[i][0], points[i][1]];
3572 for (var j = 1; j < n; ++j) {
3573 for (i = 0; i < n - j; ++i) {
3574 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3575 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3579 return [ tmp[0][0], tmp[0][1] ];
3583 * Portions of this file are based on pieces of Yahoo User Interface Library
3584 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3585 * YUI licensed under the BSD License:
3586 * http://developer.yahoo.net/yui/license.txt
3587 * <script type="text/javascript">
3592 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3593 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3596 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3598 var fly = Roo.lib.AnimBase.fly;
3600 var superclass = Y.ColorAnim.superclass;
3601 var proto = Y.ColorAnim.prototype;
3603 proto.toString = function() {
3604 var el = this.getEl();
3605 var id = el.id || el.tagName;
3606 return ("ColorAnim " + id);
3609 proto.patterns.color = /color$/i;
3610 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3611 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3612 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3613 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3616 proto.parseColor = function(s) {
3617 if (s.length == 3) {
3621 var c = this.patterns.hex.exec(s);
3622 if (c && c.length == 4) {
3623 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3626 c = this.patterns.rgb.exec(s);
3627 if (c && c.length == 4) {
3628 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3631 c = this.patterns.hex3.exec(s);
3632 if (c && c.length == 4) {
3633 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3638 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3639 proto.getAttribute = function(attr) {
3640 var el = this.getEl();
3641 if (this.patterns.color.test(attr)) {
3642 var val = fly(el).getStyle(attr);
3644 if (this.patterns.transparent.test(val)) {
3645 var parent = el.parentNode;
3646 val = fly(parent).getStyle(attr);
3648 while (parent && this.patterns.transparent.test(val)) {
3649 parent = parent.parentNode;
3650 val = fly(parent).getStyle(attr);
3651 if (parent.tagName.toUpperCase() == 'HTML') {
3657 val = superclass.getAttribute.call(this, attr);
3662 proto.getAttribute = function(attr) {
3663 var el = this.getEl();
3664 if (this.patterns.color.test(attr)) {
3665 var val = fly(el).getStyle(attr);
3667 if (this.patterns.transparent.test(val)) {
3668 var parent = el.parentNode;
3669 val = fly(parent).getStyle(attr);
3671 while (parent && this.patterns.transparent.test(val)) {
3672 parent = parent.parentNode;
3673 val = fly(parent).getStyle(attr);
3674 if (parent.tagName.toUpperCase() == 'HTML') {
3680 val = superclass.getAttribute.call(this, attr);
3686 proto.doMethod = function(attr, start, end) {
3689 if (this.patterns.color.test(attr)) {
3691 for (var i = 0, len = start.length; i < len; ++i) {
3692 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3695 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3698 val = superclass.doMethod.call(this, attr, start, end);
3704 proto.setRuntimeAttribute = function(attr) {
3705 superclass.setRuntimeAttribute.call(this, attr);
3707 if (this.patterns.color.test(attr)) {
3708 var attributes = this.attributes;
3709 var start = this.parseColor(this.runtimeAttributes[attr].start);
3710 var end = this.parseColor(this.runtimeAttributes[attr].end);
3712 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3713 end = this.parseColor(attributes[attr].by);
3715 for (var i = 0, len = start.length; i < len; ++i) {
3716 end[i] = start[i] + end[i];
3720 this.runtimeAttributes[attr].start = start;
3721 this.runtimeAttributes[attr].end = end;
3727 * Portions of this file are based on pieces of Yahoo User Interface Library
3728 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3729 * YUI licensed under the BSD License:
3730 * http://developer.yahoo.net/yui/license.txt
3731 * <script type="text/javascript">
3737 easeNone: function (t, b, c, d) {
3738 return c * t / d + b;
3742 easeIn: function (t, b, c, d) {
3743 return c * (t /= d) * t + b;
3747 easeOut: function (t, b, c, d) {
3748 return -c * (t /= d) * (t - 2) + b;
3752 easeBoth: function (t, b, c, d) {
3753 if ((t /= d / 2) < 1) {
3754 return c / 2 * t * t + b;
3757 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3761 easeInStrong: function (t, b, c, d) {
3762 return c * (t /= d) * t * t * t + b;
3766 easeOutStrong: function (t, b, c, d) {
3767 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3771 easeBothStrong: function (t, b, c, d) {
3772 if ((t /= d / 2) < 1) {
3773 return c / 2 * t * t * t * t + b;
3776 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3781 elasticIn: function (t, b, c, d, a, p) {
3785 if ((t /= d) == 1) {
3792 if (!a || a < Math.abs(c)) {
3797 var s = p / (2 * Math.PI) * Math.asin(c / a);
3800 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3804 elasticOut: function (t, b, c, d, a, p) {
3808 if ((t /= d) == 1) {
3815 if (!a || a < Math.abs(c)) {
3820 var s = p / (2 * Math.PI) * Math.asin(c / a);
3823 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3827 elasticBoth: function (t, b, c, d, a, p) {
3832 if ((t /= d / 2) == 2) {
3840 if (!a || a < Math.abs(c)) {
3845 var s = p / (2 * Math.PI) * Math.asin(c / a);
3849 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3850 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3852 return a * Math.pow(2, -10 * (t -= 1)) *
3853 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3858 backIn: function (t, b, c, d, s) {
3859 if (typeof s == 'undefined') {
3862 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3866 backOut: function (t, b, c, d, s) {
3867 if (typeof s == 'undefined') {
3870 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3874 backBoth: function (t, b, c, d, s) {
3875 if (typeof s == 'undefined') {
3879 if ((t /= d / 2 ) < 1) {
3880 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3882 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3886 bounceIn: function (t, b, c, d) {
3887 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3891 bounceOut: function (t, b, c, d) {
3892 if ((t /= d) < (1 / 2.75)) {
3893 return c * (7.5625 * t * t) + b;
3894 } else if (t < (2 / 2.75)) {
3895 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3896 } else if (t < (2.5 / 2.75)) {
3897 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3899 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3903 bounceBoth: function (t, b, c, d) {
3905 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3907 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3910 * Portions of this file are based on pieces of Yahoo User Interface Library
3911 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3912 * YUI licensed under the BSD License:
3913 * http://developer.yahoo.net/yui/license.txt
3914 * <script type="text/javascript">
3918 Roo.lib.Motion = function(el, attributes, duration, method) {
3920 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3924 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3928 var superclass = Y.Motion.superclass;
3929 var proto = Y.Motion.prototype;
3931 proto.toString = function() {
3932 var el = this.getEl();
3933 var id = el.id || el.tagName;
3934 return ("Motion " + id);
3937 proto.patterns.points = /^points$/i;
3939 proto.setAttribute = function(attr, val, unit) {
3940 if (this.patterns.points.test(attr)) {
3941 unit = unit || 'px';
3942 superclass.setAttribute.call(this, 'left', val[0], unit);
3943 superclass.setAttribute.call(this, 'top', val[1], unit);
3945 superclass.setAttribute.call(this, attr, val, unit);
3949 proto.getAttribute = function(attr) {
3950 if (this.patterns.points.test(attr)) {
3952 superclass.getAttribute.call(this, 'left'),
3953 superclass.getAttribute.call(this, 'top')
3956 val = superclass.getAttribute.call(this, attr);
3962 proto.doMethod = function(attr, start, end) {
3965 if (this.patterns.points.test(attr)) {
3966 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3967 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3969 val = superclass.doMethod.call(this, attr, start, end);
3974 proto.setRuntimeAttribute = function(attr) {
3975 if (this.patterns.points.test(attr)) {
3976 var el = this.getEl();
3977 var attributes = this.attributes;
3979 var control = attributes['points']['control'] || [];
3983 if (control.length > 0 && !(control[0] instanceof Array)) {
3984 control = [control];
3987 for (i = 0,len = control.length; i < len; ++i) {
3988 tmp[i] = control[i];
3993 Roo.fly(el).position();
3995 if (isset(attributes['points']['from'])) {
3996 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3999 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4002 start = this.getAttribute('points');
4005 if (isset(attributes['points']['to'])) {
4006 end = translateValues.call(this, attributes['points']['to'], start);
4008 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009 for (i = 0,len = control.length; i < len; ++i) {
4010 control[i] = translateValues.call(this, control[i], start);
4014 } else if (isset(attributes['points']['by'])) {
4015 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4017 for (i = 0,len = control.length; i < len; ++i) {
4018 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4022 this.runtimeAttributes[attr] = [start];
4024 if (control.length > 0) {
4025 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4028 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4031 superclass.setRuntimeAttribute.call(this, attr);
4035 var translateValues = function(val, start) {
4036 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4037 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4042 var isset = function(prop) {
4043 return (typeof prop !== 'undefined');
4047 * Portions of this file are based on pieces of Yahoo User Interface Library
4048 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4049 * YUI licensed under the BSD License:
4050 * http://developer.yahoo.net/yui/license.txt
4051 * <script type="text/javascript">
4055 Roo.lib.Scroll = function(el, attributes, duration, method) {
4057 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4061 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4065 var superclass = Y.Scroll.superclass;
4066 var proto = Y.Scroll.prototype;
4068 proto.toString = function() {
4069 var el = this.getEl();
4070 var id = el.id || el.tagName;
4071 return ("Scroll " + id);
4074 proto.doMethod = function(attr, start, end) {
4077 if (attr == 'scroll') {
4079 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4080 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4084 val = superclass.doMethod.call(this, attr, start, end);
4089 proto.getAttribute = function(attr) {
4091 var el = this.getEl();
4093 if (attr == 'scroll') {
4094 val = [ el.scrollLeft, el.scrollTop ];
4096 val = superclass.getAttribute.call(this, attr);
4102 proto.setAttribute = function(attr, val, unit) {
4103 var el = this.getEl();
4105 if (attr == 'scroll') {
4106 el.scrollLeft = val[0];
4107 el.scrollTop = val[1];
4109 superclass.setAttribute.call(this, attr, val, unit);
4115 * Ext JS Library 1.1.1
4116 * Copyright(c) 2006-2007, Ext JS, LLC.
4118 * Originally Released Under LGPL - original licence link has changed is not relivant.
4121 * <script type="text/javascript">
4125 // nasty IE9 hack - what a pile of crap that is..
4127 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4128 Range.prototype.createContextualFragment = function (html) {
4129 var doc = window.document;
4130 var container = doc.createElement("div");
4131 container.innerHTML = html;
4132 var frag = doc.createDocumentFragment(), n;
4133 while ((n = container.firstChild)) {
4134 frag.appendChild(n);
4141 * @class Roo.DomHelper
4142 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4143 * 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>.
4146 Roo.DomHelper = function(){
4147 var tempTableEl = null;
4148 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4149 var tableRe = /^table|tbody|tr|td$/i;
4151 // build as innerHTML where available
4153 var createHtml = function(o){
4154 if(typeof o == 'string'){
4163 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4164 if(attr == "style"){
4166 if(typeof s == "function"){
4169 if(typeof s == "string"){
4170 b += ' style="' + s + '"';
4171 }else if(typeof s == "object"){
4174 if(typeof s[key] != "function"){
4175 b += key + ":" + s[key] + ";";
4182 b += ' class="' + o["cls"] + '"';
4183 }else if(attr == "htmlFor"){
4184 b += ' for="' + o["htmlFor"] + '"';
4186 b += " " + attr + '="' + o[attr] + '"';
4190 if(emptyTags.test(o.tag)){
4194 var cn = o.children || o.cn;
4196 //http://bugs.kde.org/show_bug.cgi?id=71506
4197 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198 for(var i = 0, len = cn.length; i < len; i++) {
4199 b += createHtml(cn[i], b);
4202 b += createHtml(cn, b);
4208 b += "</" + o.tag + ">";
4215 var createDom = function(o, parentNode){
4217 // defininition craeted..
4219 if (o.ns && o.ns != 'html') {
4221 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4222 xmlns[o.ns] = o.xmlns;
4225 if (typeof(xmlns[o.ns]) == 'undefined') {
4226 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4232 if (typeof(o) == 'string') {
4233 return parentNode.appendChild(document.createTextNode(o));
4235 o.tag = o.tag || div;
4236 if (o.ns && Roo.isIE) {
4238 o.tag = o.ns + ':' + o.tag;
4241 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4242 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4245 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4246 attr == "style" || typeof o[attr] == "function") { continue; }
4248 if(attr=="cls" && Roo.isIE){
4249 el.className = o["cls"];
4251 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4257 Roo.DomHelper.applyStyles(el, o.style);
4258 var cn = o.children || o.cn;
4260 //http://bugs.kde.org/show_bug.cgi?id=71506
4261 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4262 for(var i = 0, len = cn.length; i < len; i++) {
4263 createDom(cn[i], el);
4270 el.innerHTML = o.html;
4273 parentNode.appendChild(el);
4278 var ieTable = function(depth, s, h, e){
4279 tempTableEl.innerHTML = [s, h, e].join('');
4280 var i = -1, el = tempTableEl;
4287 // kill repeat to save bytes
4291 tbe = '</tbody>'+te,
4297 * Nasty code for IE's broken table implementation
4299 var insertIntoTable = function(tag, where, el, html){
4301 tempTableEl = document.createElement('div');
4306 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4309 if(where == 'beforebegin'){
4313 before = el.nextSibling;
4316 node = ieTable(4, trs, html, tre);
4318 else if(tag == 'tr'){
4319 if(where == 'beforebegin'){
4322 node = ieTable(3, tbs, html, tbe);
4323 } else if(where == 'afterend'){
4324 before = el.nextSibling;
4326 node = ieTable(3, tbs, html, tbe);
4327 } else{ // INTO a TR
4328 if(where == 'afterbegin'){
4329 before = el.firstChild;
4331 node = ieTable(4, trs, html, tre);
4333 } else if(tag == 'tbody'){
4334 if(where == 'beforebegin'){
4337 node = ieTable(2, ts, html, te);
4338 } else if(where == 'afterend'){
4339 before = el.nextSibling;
4341 node = ieTable(2, ts, html, te);
4343 if(where == 'afterbegin'){
4344 before = el.firstChild;
4346 node = ieTable(3, tbs, html, tbe);
4349 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4352 if(where == 'afterbegin'){
4353 before = el.firstChild;
4355 node = ieTable(2, ts, html, te);
4357 el.insertBefore(node, before);
4362 /** True to force the use of DOM instead of html fragments @type Boolean */
4366 * Returns the markup for the passed Element(s) config
4367 * @param {Object} o The Dom object spec (and children)
4370 markup : function(o){
4371 return createHtml(o);
4375 * Applies a style specification to an element
4376 * @param {String/HTMLElement} el The element to apply styles to
4377 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4378 * a function which returns such a specification.
4380 applyStyles : function(el, styles){
4383 if(typeof styles == "string"){
4384 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4386 while ((matches = re.exec(styles)) != null){
4387 el.setStyle(matches[1], matches[2]);
4389 }else if (typeof styles == "object"){
4390 for (var style in styles){
4391 el.setStyle(style, styles[style]);
4393 }else if (typeof styles == "function"){
4394 Roo.DomHelper.applyStyles(el, styles.call());
4400 * Inserts an HTML fragment into the Dom
4401 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4402 * @param {HTMLElement} el The context element
4403 * @param {String} html The HTML fragmenet
4404 * @return {HTMLElement} The new node
4406 insertHtml : function(where, el, html){
4407 where = where.toLowerCase();
4408 if(el.insertAdjacentHTML){
4409 if(tableRe.test(el.tagName)){
4411 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4417 el.insertAdjacentHTML('BeforeBegin', html);
4418 return el.previousSibling;
4420 el.insertAdjacentHTML('AfterBegin', html);
4421 return el.firstChild;
4423 el.insertAdjacentHTML('BeforeEnd', html);
4424 return el.lastChild;
4426 el.insertAdjacentHTML('AfterEnd', html);
4427 return el.nextSibling;
4429 throw 'Illegal insertion point -> "' + where + '"';
4431 var range = el.ownerDocument.createRange();
4435 range.setStartBefore(el);
4436 frag = range.createContextualFragment(html);
4437 el.parentNode.insertBefore(frag, el);
4438 return el.previousSibling;
4441 range.setStartBefore(el.firstChild);
4442 frag = range.createContextualFragment(html);
4443 el.insertBefore(frag, el.firstChild);
4444 return el.firstChild;
4446 el.innerHTML = html;
4447 return el.firstChild;
4451 range.setStartAfter(el.lastChild);
4452 frag = range.createContextualFragment(html);
4453 el.appendChild(frag);
4454 return el.lastChild;
4456 el.innerHTML = html;
4457 return el.lastChild;
4460 range.setStartAfter(el);
4461 frag = range.createContextualFragment(html);
4462 el.parentNode.insertBefore(frag, el.nextSibling);
4463 return el.nextSibling;
4465 throw 'Illegal insertion point -> "' + where + '"';
4469 * Creates new Dom element(s) and inserts them before el
4470 * @param {String/HTMLElement/Element} el The context element
4471 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4472 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473 * @return {HTMLElement/Roo.Element} The new node
4475 insertBefore : function(el, o, returnElement){
4476 return this.doInsert(el, o, returnElement, "beforeBegin");
4480 * Creates new Dom element(s) and inserts them after el
4481 * @param {String/HTMLElement/Element} el The context element
4482 * @param {Object} o The Dom object spec (and children)
4483 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484 * @return {HTMLElement/Roo.Element} The new node
4486 insertAfter : function(el, o, returnElement){
4487 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4491 * Creates new Dom element(s) and inserts them as the first child of el
4492 * @param {String/HTMLElement/Element} el The context element
4493 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495 * @return {HTMLElement/Roo.Element} The new node
4497 insertFirst : function(el, o, returnElement){
4498 return this.doInsert(el, o, returnElement, "afterBegin");
4502 doInsert : function(el, o, returnElement, pos, sibling){
4503 el = Roo.getDom(el);
4505 if(this.useDom || o.ns){
4506 newNode = createDom(o, null);
4507 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4509 var html = createHtml(o);
4510 newNode = this.insertHtml(pos, el, html);
4512 return returnElement ? Roo.get(newNode, true) : newNode;
4516 * Creates new Dom element(s) and appends them to el
4517 * @param {String/HTMLElement/Element} el The context element
4518 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4519 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520 * @return {HTMLElement/Roo.Element} The new node
4522 append : function(el, o, returnElement){
4523 el = Roo.getDom(el);
4525 if(this.useDom || o.ns){
4526 newNode = createDom(o, null);
4527 el.appendChild(newNode);
4529 var html = createHtml(o);
4530 newNode = this.insertHtml("beforeEnd", el, html);
4532 return returnElement ? Roo.get(newNode, true) : newNode;
4536 * Creates new Dom element(s) and overwrites the contents of el with them
4537 * @param {String/HTMLElement/Element} el The context element
4538 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4539 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4540 * @return {HTMLElement/Roo.Element} The new node
4542 overwrite : function(el, o, returnElement){
4543 el = Roo.getDom(el);
4546 while (el.childNodes.length) {
4547 el.removeChild(el.firstChild);
4551 el.innerHTML = createHtml(o);
4554 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558 * Creates a new Roo.DomHelper.Template from the Dom object spec
4559 * @param {Object} o The Dom object spec (and children)
4560 * @return {Roo.DomHelper.Template} The new template
4562 createTemplate : function(o){
4563 var html = createHtml(o);
4564 return new Roo.Template(html);
4570 * Ext JS Library 1.1.1
4571 * Copyright(c) 2006-2007, Ext JS, LLC.
4573 * Originally Released Under LGPL - original licence link has changed is not relivant.
4576 * <script type="text/javascript">
4580 * @class Roo.Template
4581 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4582 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4585 var t = new Roo.Template({
4586 html : '<div name="{id}">' +
4587 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4589 myformat: function (value, allValues) {
4590 return 'XX' + value;
4593 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4595 * For more information see this blog post with examples:
4596 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4597 - Create Elements using DOM, HTML fragments and Templates</a>.
4599 * @param {Object} cfg - Configuration object.
4601 Roo.Template = function(cfg){
4603 if(cfg instanceof Array){
4605 }else if(arguments.length > 1){
4606 cfg = Array.prototype.join.call(arguments, "");
4610 if (typeof(cfg) == 'object') {
4621 Roo.Template.prototype = {
4624 * @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..
4625 * it should be fixed so that template is observable...
4629 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4633 * Returns an HTML fragment of this template with the specified values applied.
4634 * @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'})
4635 * @return {String} The HTML fragment
4637 applyTemplate : function(values){
4641 return this.compiled(values);
4643 var useF = this.disableFormats !== true;
4644 var fm = Roo.util.Format, tpl = this;
4645 var fn = function(m, name, format, args){
4647 if(format.substr(0, 5) == "this."){
4648 return tpl.call(format.substr(5), values[name], values);
4651 // quoted values are required for strings in compiled templates,
4652 // but for non compiled we need to strip them
4653 // quoted reversed for jsmin
4654 var re = /^\s*['"](.*)["']\s*$/;
4655 args = args.split(',');
4656 for(var i = 0, len = args.length; i < len; i++){
4657 args[i] = args[i].replace(re, "$1");
4659 args = [values[name]].concat(args);
4661 args = [values[name]];
4663 return fm[format].apply(fm, args);
4666 return values[name] !== undefined ? values[name] : "";
4669 return this.html.replace(this.re, fn);
4687 this.loading = true;
4688 this.compiled = false;
4690 var cx = new Roo.data.Connection();
4694 success : function (response) {
4696 _t.html = response.responseText;
4700 failure : function(response) {
4701 Roo.log("Template failed to load from " + _t.url);
4708 * Sets the HTML used as the template and optionally compiles it.
4709 * @param {String} html
4710 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4711 * @return {Roo.Template} this
4713 set : function(html, compile){
4715 this.compiled = null;
4723 * True to disable format functions (defaults to false)
4726 disableFormats : false,
4729 * The regular expression used to match template variables
4733 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4736 * Compiles the template into an internal function, eliminating the RegEx overhead.
4737 * @return {Roo.Template} this
4739 compile : function(){
4740 var fm = Roo.util.Format;
4741 var useF = this.disableFormats !== true;
4742 var sep = Roo.isGecko ? "+" : ",";
4743 var fn = function(m, name, format, args){
4745 args = args ? ',' + args : "";
4746 if(format.substr(0, 5) != "this."){
4747 format = "fm." + format + '(';
4749 format = 'this.call("'+ format.substr(5) + '", ';
4753 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4755 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4758 // branched to use + in gecko and [].join() in others
4760 body = "this.compiled = function(values){ return '" +
4761 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4764 body = ["this.compiled = function(values){ return ['"];
4765 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4766 body.push("'].join('');};");
4767 body = body.join('');
4777 // private function used to call members
4778 call : function(fnName, value, allValues){
4779 return this[fnName](value, allValues);
4783 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4784 * @param {String/HTMLElement/Roo.Element} el The context element
4785 * @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'})
4786 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787 * @return {HTMLElement/Roo.Element} The new node or Element
4789 insertFirst: function(el, values, returnElement){
4790 return this.doInsert('afterBegin', el, values, returnElement);
4794 * Applies the supplied values to the template and inserts the new node(s) before el.
4795 * @param {String/HTMLElement/Roo.Element} el The context element
4796 * @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'})
4797 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798 * @return {HTMLElement/Roo.Element} The new node or Element
4800 insertBefore: function(el, values, returnElement){
4801 return this.doInsert('beforeBegin', el, values, returnElement);
4805 * Applies the supplied values to the template and inserts the new node(s) after el.
4806 * @param {String/HTMLElement/Roo.Element} el The context element
4807 * @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'})
4808 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4809 * @return {HTMLElement/Roo.Element} The new node or Element
4811 insertAfter : function(el, values, returnElement){
4812 return this.doInsert('afterEnd', el, values, returnElement);
4816 * Applies the supplied values to the template and appends the new node(s) to el.
4817 * @param {String/HTMLElement/Roo.Element} el The context element
4818 * @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'})
4819 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820 * @return {HTMLElement/Roo.Element} The new node or Element
4822 append : function(el, values, returnElement){
4823 return this.doInsert('beforeEnd', el, values, returnElement);
4826 doInsert : function(where, el, values, returnEl){
4827 el = Roo.getDom(el);
4828 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4829 return returnEl ? Roo.get(newNode, true) : newNode;
4833 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4834 * @param {String/HTMLElement/Roo.Element} el The context element
4835 * @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'})
4836 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4837 * @return {HTMLElement/Roo.Element} The new node or Element
4839 overwrite : function(el, values, returnElement){
4840 el = Roo.getDom(el);
4841 el.innerHTML = this.applyTemplate(values);
4842 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4846 * Alias for {@link #applyTemplate}
4849 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4852 Roo.DomHelper.Template = Roo.Template;
4855 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4856 * @param {String/HTMLElement} el A DOM element or its id
4857 * @returns {Roo.Template} The created template
4860 Roo.Template.from = function(el){
4861 el = Roo.getDom(el);
4862 return new Roo.Template(el.value || el.innerHTML);
4865 * Ext JS Library 1.1.1
4866 * Copyright(c) 2006-2007, Ext JS, LLC.
4868 * Originally Released Under LGPL - original licence link has changed is not relivant.
4871 * <script type="text/javascript">
4876 * This is code is also distributed under MIT license for use
4877 * with jQuery and prototype JavaScript libraries.
4880 * @class Roo.DomQuery
4881 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).
4883 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>
4886 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.
4888 <h4>Element Selectors:</h4>
4890 <li> <b>*</b> any element</li>
4891 <li> <b>E</b> an element with the tag E</li>
4892 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4893 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4894 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4895 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4897 <h4>Attribute Selectors:</h4>
4898 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4900 <li> <b>E[foo]</b> has an attribute "foo"</li>
4901 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4902 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4903 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4904 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4905 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4906 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4908 <h4>Pseudo Classes:</h4>
4910 <li> <b>E:first-child</b> E is the first child of its parent</li>
4911 <li> <b>E:last-child</b> E is the last child of its parent</li>
4912 <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>
4913 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4914 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4915 <li> <b>E:only-child</b> E is the only child of its parent</li>
4916 <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>
4917 <li> <b>E:first</b> the first E in the resultset</li>
4918 <li> <b>E:last</b> the last E in the resultset</li>
4919 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4920 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4921 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4922 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4923 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4924 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4925 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4926 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4927 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4929 <h4>CSS Value Selectors:</h4>
4931 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4932 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4933 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4934 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4935 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4936 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4940 Roo.DomQuery = function(){
4941 var cache = {}, simpleCache = {}, valueCache = {};
4942 var nonSpace = /\S/;
4943 var trimRe = /^\s+|\s+$/g;
4944 var tplRe = /\{(\d+)\}/g;
4945 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4946 var tagTokenRe = /^(#)?([\w-\*]+)/;
4947 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4949 function child(p, index){
4951 var n = p.firstChild;
4953 if(n.nodeType == 1){
4964 while((n = n.nextSibling) && n.nodeType != 1);
4969 while((n = n.previousSibling) && n.nodeType != 1);
4973 function children(d){
4974 var n = d.firstChild, ni = -1;
4976 var nx = n.nextSibling;
4977 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4987 function byClassName(c, a, v){
4991 var r = [], ri = -1, cn;
4992 for(var i = 0, ci; ci = c[i]; i++){
4993 if((' '+ci.className+' ').indexOf(v) != -1){
5000 function attrValue(n, attr){
5001 if(!n.tagName && typeof n.length != "undefined"){
5010 if(attr == "class" || attr == "className"){
5013 return n.getAttribute(attr) || n[attr];
5017 function getNodes(ns, mode, tagName){
5018 var result = [], ri = -1, cs;
5022 tagName = tagName || "*";
5023 if(typeof ns.getElementsByTagName != "undefined"){
5027 for(var i = 0, ni; ni = ns[i]; i++){
5028 cs = ni.getElementsByTagName(tagName);
5029 for(var j = 0, ci; ci = cs[j]; j++){
5033 }else if(mode == "/" || mode == ">"){
5034 var utag = tagName.toUpperCase();
5035 for(var i = 0, ni, cn; ni = ns[i]; i++){
5036 cn = ni.children || ni.childNodes;
5037 for(var j = 0, cj; cj = cn[j]; j++){
5038 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5043 }else if(mode == "+"){
5044 var utag = tagName.toUpperCase();
5045 for(var i = 0, n; n = ns[i]; i++){
5046 while((n = n.nextSibling) && n.nodeType != 1);
5047 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5051 }else if(mode == "~"){
5052 for(var i = 0, n; n = ns[i]; i++){
5053 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5062 function concat(a, b){
5066 for(var i = 0, l = b.length; i < l; i++){
5072 function byTag(cs, tagName){
5073 if(cs.tagName || cs == document){
5079 var r = [], ri = -1;
5080 tagName = tagName.toLowerCase();
5081 for(var i = 0, ci; ci = cs[i]; i++){
5082 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5089 function byId(cs, attr, id){
5090 if(cs.tagName || cs == document){
5096 var r = [], ri = -1;
5097 for(var i = 0,ci; ci = cs[i]; i++){
5098 if(ci && ci.id == id){
5106 function byAttribute(cs, attr, value, op, custom){
5107 var r = [], ri = -1, st = custom=="{";
5108 var f = Roo.DomQuery.operators[op];
5109 for(var i = 0, ci; ci = cs[i]; i++){
5112 a = Roo.DomQuery.getStyle(ci, attr);
5114 else if(attr == "class" || attr == "className"){
5116 }else if(attr == "for"){
5118 }else if(attr == "href"){
5119 a = ci.getAttribute("href", 2);
5121 a = ci.getAttribute(attr);
5123 if((f && f(a, value)) || (!f && a)){
5130 function byPseudo(cs, name, value){
5131 return Roo.DomQuery.pseudos[name](cs, value);
5134 // This is for IE MSXML which does not support expandos.
5135 // IE runs the same speed using setAttribute, however FF slows way down
5136 // and Safari completely fails so they need to continue to use expandos.
5137 var isIE = window.ActiveXObject ? true : false;
5139 // this eval is stop the compressor from
5140 // renaming the variable to something shorter
5142 /** eval:var:batch */
5147 function nodupIEXml(cs){
5149 cs[0].setAttribute("_nodup", d);
5151 for(var i = 1, len = cs.length; i < len; i++){
5153 if(!c.getAttribute("_nodup") != d){
5154 c.setAttribute("_nodup", d);
5158 for(var i = 0, len = cs.length; i < len; i++){
5159 cs[i].removeAttribute("_nodup");
5168 var len = cs.length, c, i, r = cs, cj, ri = -1;
5169 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5172 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5173 return nodupIEXml(cs);
5177 for(i = 1; c = cs[i]; i++){
5182 for(var j = 0; j < i; j++){
5185 for(j = i+1; cj = cs[j]; j++){
5197 function quickDiffIEXml(c1, c2){
5199 for(var i = 0, len = c1.length; i < len; i++){
5200 c1[i].setAttribute("_qdiff", d);
5203 for(var i = 0, len = c2.length; i < len; i++){
5204 if(c2[i].getAttribute("_qdiff") != d){
5205 r[r.length] = c2[i];
5208 for(var i = 0, len = c1.length; i < len; i++){
5209 c1[i].removeAttribute("_qdiff");
5214 function quickDiff(c1, c2){
5215 var len1 = c1.length;
5219 if(isIE && c1[0].selectSingleNode){
5220 return quickDiffIEXml(c1, c2);
5223 for(var i = 0; i < len1; i++){
5227 for(var i = 0, len = c2.length; i < len; i++){
5228 if(c2[i]._qdiff != d){
5229 r[r.length] = c2[i];
5235 function quickId(ns, mode, root, id){
5237 var d = root.ownerDocument || root;
5238 return d.getElementById(id);
5240 ns = getNodes(ns, mode, "*");
5241 return byId(ns, null, id);
5245 getStyle : function(el, name){
5246 return Roo.fly(el).getStyle(name);
5249 * Compiles a selector/xpath query into a reusable function. The returned function
5250 * takes one parameter "root" (optional), which is the context node from where the query should start.
5251 * @param {String} selector The selector/xpath query
5252 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5253 * @return {Function}
5255 compile : function(path, type){
5256 type = type || "select";
5258 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5259 var q = path, mode, lq;
5260 var tk = Roo.DomQuery.matchers;
5261 var tklen = tk.length;
5264 // accept leading mode switch
5265 var lmode = q.match(modeRe);
5266 if(lmode && lmode[1]){
5267 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5268 q = q.replace(lmode[1], "");
5270 // strip leading slashes
5271 while(path.substr(0, 1)=="/"){
5272 path = path.substr(1);
5275 while(q && lq != q){
5277 var tm = q.match(tagTokenRe);
5278 if(type == "select"){
5281 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5283 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5285 q = q.replace(tm[0], "");
5286 }else if(q.substr(0, 1) != '@'){
5287 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5292 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5294 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5296 q = q.replace(tm[0], "");
5299 while(!(mm = q.match(modeRe))){
5300 var matched = false;
5301 for(var j = 0; j < tklen; j++){
5303 var m = q.match(t.re);
5305 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5308 q = q.replace(m[0], "");
5313 // prevent infinite loop on bad selector
5315 throw 'Error parsing selector, parsing failed at "' + q + '"';
5319 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5320 q = q.replace(mm[1], "");
5323 fn[fn.length] = "return nodup(n);\n}";
5326 * list of variables that need from compression as they are used by eval.
5336 * eval:var:byClassName
5338 * eval:var:byAttribute
5339 * eval:var:attrValue
5347 * Selects a group of elements.
5348 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 select : function(path, root, type){
5353 if(!root || root == document){
5356 if(typeof root == "string"){
5357 root = document.getElementById(root);
5359 var paths = path.split(",");
5361 for(var i = 0, len = paths.length; i < len; i++){
5362 var p = paths[i].replace(trimRe, "");
5364 cache[p] = Roo.DomQuery.compile(p);
5366 throw p + " is not a valid selector";
5369 var result = cache[p](root);
5370 if(result && result != document){
5371 results = results.concat(result);
5374 if(paths.length > 1){
5375 return nodup(results);
5381 * Selects a single element.
5382 * @param {String} selector The selector/xpath query
5383 * @param {Node} root (optional) The start of the query (defaults to document).
5386 selectNode : function(path, root){
5387 return Roo.DomQuery.select(path, root)[0];
5391 * Selects the value of a node, optionally replacing null with the defaultValue.
5392 * @param {String} selector The selector/xpath query
5393 * @param {Node} root (optional) The start of the query (defaults to document).
5394 * @param {String} defaultValue
5396 selectValue : function(path, root, defaultValue){
5397 path = path.replace(trimRe, "");
5398 if(!valueCache[path]){
5399 valueCache[path] = Roo.DomQuery.compile(path, "select");
5401 var n = valueCache[path](root);
5402 n = n[0] ? n[0] : n;
5403 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5404 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5408 * Selects the value of a node, parsing integers and floats.
5409 * @param {String} selector The selector/xpath query
5410 * @param {Node} root (optional) The start of the query (defaults to document).
5411 * @param {Number} defaultValue
5414 selectNumber : function(path, root, defaultValue){
5415 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5416 return parseFloat(v);
5420 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5421 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5422 * @param {String} selector The simple selector to test
5425 is : function(el, ss){
5426 if(typeof el == "string"){
5427 el = document.getElementById(el);
5429 var isArray = (el instanceof Array);
5430 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5431 return isArray ? (result.length == el.length) : (result.length > 0);
5435 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5436 * @param {Array} el An array of elements to filter
5437 * @param {String} selector The simple selector to test
5438 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5439 * the selector instead of the ones that match
5442 filter : function(els, ss, nonMatches){
5443 ss = ss.replace(trimRe, "");
5444 if(!simpleCache[ss]){
5445 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5447 var result = simpleCache[ss](els);
5448 return nonMatches ? quickDiff(result, els) : result;
5452 * Collection of matching regular expressions and code snippets.
5456 select: 'n = byClassName(n, null, " {1} ");'
5458 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5459 select: 'n = byPseudo(n, "{1}", "{2}");'
5461 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5462 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5465 select: 'n = byId(n, null, "{1}");'
5468 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5473 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5474 * 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, > <.
5477 "=" : function(a, v){
5480 "!=" : function(a, v){
5483 "^=" : function(a, v){
5484 return a && a.substr(0, v.length) == v;
5486 "$=" : function(a, v){
5487 return a && a.substr(a.length-v.length) == v;
5489 "*=" : function(a, v){
5490 return a && a.indexOf(v) !== -1;
5492 "%=" : function(a, v){
5493 return (a % v) == 0;
5495 "|=" : function(a, v){
5496 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5498 "~=" : function(a, v){
5499 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5504 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5505 * and the argument (if any) supplied in the selector.
5508 "first-child" : function(c){
5509 var r = [], ri = -1, n;
5510 for(var i = 0, ci; ci = n = c[i]; i++){
5511 while((n = n.previousSibling) && n.nodeType != 1);
5519 "last-child" : function(c){
5520 var r = [], ri = -1, n;
5521 for(var i = 0, ci; ci = n = c[i]; i++){
5522 while((n = n.nextSibling) && n.nodeType != 1);
5530 "nth-child" : function(c, a) {
5531 var r = [], ri = -1;
5532 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5533 var f = (m[1] || 1) - 0, l = m[2] - 0;
5534 for(var i = 0, n; n = c[i]; i++){
5535 var pn = n.parentNode;
5536 if (batch != pn._batch) {
5538 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5539 if(cn.nodeType == 1){
5546 if (l == 0 || n.nodeIndex == l){
5549 } else if ((n.nodeIndex + l) % f == 0){
5557 "only-child" : function(c){
5558 var r = [], ri = -1;;
5559 for(var i = 0, ci; ci = c[i]; i++){
5560 if(!prev(ci) && !next(ci)){
5567 "empty" : function(c){
5568 var r = [], ri = -1;
5569 for(var i = 0, ci; ci = c[i]; i++){
5570 var cns = ci.childNodes, j = 0, cn, empty = true;
5573 if(cn.nodeType == 1 || cn.nodeType == 3){
5585 "contains" : function(c, v){
5586 var r = [], ri = -1;
5587 for(var i = 0, ci; ci = c[i]; i++){
5588 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5595 "nodeValue" : function(c, v){
5596 var r = [], ri = -1;
5597 for(var i = 0, ci; ci = c[i]; i++){
5598 if(ci.firstChild && ci.firstChild.nodeValue == v){
5605 "checked" : function(c){
5606 var r = [], ri = -1;
5607 for(var i = 0, ci; ci = c[i]; i++){
5608 if(ci.checked == true){
5615 "not" : function(c, ss){
5616 return Roo.DomQuery.filter(c, ss, true);
5619 "odd" : function(c){
5620 return this["nth-child"](c, "odd");
5623 "even" : function(c){
5624 return this["nth-child"](c, "even");
5627 "nth" : function(c, a){
5628 return c[a-1] || [];
5631 "first" : function(c){
5635 "last" : function(c){
5636 return c[c.length-1] || [];
5639 "has" : function(c, ss){
5640 var s = Roo.DomQuery.select;
5641 var r = [], ri = -1;
5642 for(var i = 0, ci; ci = c[i]; i++){
5643 if(s(ss, ci).length > 0){
5650 "next" : function(c, ss){
5651 var is = Roo.DomQuery.is;
5652 var r = [], ri = -1;
5653 for(var i = 0, ci; ci = c[i]; i++){
5662 "prev" : function(c, ss){
5663 var is = Roo.DomQuery.is;
5664 var r = [], ri = -1;
5665 for(var i = 0, ci; ci = c[i]; i++){
5678 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5679 * @param {String} path The selector/xpath query
5680 * @param {Node} root (optional) The start of the query (defaults to document).
5685 Roo.query = Roo.DomQuery.select;
5688 * Ext JS Library 1.1.1
5689 * Copyright(c) 2006-2007, Ext JS, LLC.
5691 * Originally Released Under LGPL - original licence link has changed is not relivant.
5694 * <script type="text/javascript">
5698 * @class Roo.util.Observable
5699 * Base class that provides a common interface for publishing events. Subclasses are expected to
5700 * to have a property "events" with all the events defined.<br>
5703 Employee = function(name){
5710 Roo.extend(Employee, Roo.util.Observable);
5712 * @param {Object} config properties to use (incuding events / listeners)
5715 Roo.util.Observable = function(cfg){
5718 this.addEvents(cfg.events || {});
5720 delete cfg.events; // make sure
5723 Roo.apply(this, cfg);
5726 this.on(this.listeners);
5727 delete this.listeners;
5730 Roo.util.Observable.prototype = {
5732 * @cfg {Object} listeners list of events and functions to call for this object,
5736 'click' : function(e) {
5746 * Fires the specified event with the passed parameters (minus the event name).
5747 * @param {String} eventName
5748 * @param {Object...} args Variable number of parameters are passed to handlers
5749 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5751 fireEvent : function(){
5752 var ce = this.events[arguments[0].toLowerCase()];
5753 if(typeof ce == "object"){
5754 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5761 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5764 * Appends an event handler to this component
5765 * @param {String} eventName The type of event to listen for
5766 * @param {Function} handler The method the event invokes
5767 * @param {Object} scope (optional) The scope in which to execute the handler
5768 * function. The handler function's "this" context.
5769 * @param {Object} options (optional) An object containing handler configuration
5770 * properties. This may contain any of the following properties:<ul>
5771 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5772 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5773 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5774 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5775 * by the specified number of milliseconds. If the event fires again within that time, the original
5776 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5779 * <b>Combining Options</b><br>
5780 * Using the options argument, it is possible to combine different types of listeners:<br>
5782 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5784 el.on('click', this.onClick, this, {
5791 * <b>Attaching multiple handlers in 1 call</b><br>
5792 * The method also allows for a single argument to be passed which is a config object containing properties
5793 * which specify multiple handlers.
5802 fn: this.onMouseOver,
5806 fn: this.onMouseOut,
5812 * Or a shorthand syntax which passes the same scope object to all handlers:
5815 'click': this.onClick,
5816 'mouseover': this.onMouseOver,
5817 'mouseout': this.onMouseOut,
5822 addListener : function(eventName, fn, scope, o){
5823 if(typeof eventName == "object"){
5826 if(this.filterOptRe.test(e)){
5829 if(typeof o[e] == "function"){
5831 this.addListener(e, o[e], o.scope, o);
5833 // individual options
5834 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5839 o = (!o || typeof o == "boolean") ? {} : o;
5840 eventName = eventName.toLowerCase();
5841 var ce = this.events[eventName] || true;
5842 if(typeof ce == "boolean"){
5843 ce = new Roo.util.Event(this, eventName);
5844 this.events[eventName] = ce;
5846 ce.addListener(fn, scope, o);
5850 * Removes a listener
5851 * @param {String} eventName The type of event to listen for
5852 * @param {Function} handler The handler to remove
5853 * @param {Object} scope (optional) The scope (this object) for the handler
5855 removeListener : function(eventName, fn, scope){
5856 var ce = this.events[eventName.toLowerCase()];
5857 if(typeof ce == "object"){
5858 ce.removeListener(fn, scope);
5863 * Removes all listeners for this object
5865 purgeListeners : function(){
5866 for(var evt in this.events){
5867 if(typeof this.events[evt] == "object"){
5868 this.events[evt].clearListeners();
5873 relayEvents : function(o, events){
5874 var createHandler = function(ename){
5876 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5879 for(var i = 0, len = events.length; i < len; i++){
5880 var ename = events[i];
5881 if(!this.events[ename]){ this.events[ename] = true; };
5882 o.on(ename, createHandler(ename), this);
5887 * Used to define events on this Observable
5888 * @param {Object} object The object with the events defined
5890 addEvents : function(o){
5894 Roo.applyIf(this.events, o);
5898 * Checks to see if this object has any listeners for a specified event
5899 * @param {String} eventName The name of the event to check for
5900 * @return {Boolean} True if the event is being listened for, else false
5902 hasListener : function(eventName){
5903 var e = this.events[eventName];
5904 return typeof e == "object" && e.listeners.length > 0;
5908 * Appends an event handler to this element (shorthand for addListener)
5909 * @param {String} eventName The type of event to listen for
5910 * @param {Function} handler The method the event invokes
5911 * @param {Object} scope (optional) The scope in which to execute the handler
5912 * function. The handler function's "this" context.
5913 * @param {Object} options (optional)
5916 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5918 * Removes a listener (shorthand for removeListener)
5919 * @param {String} eventName The type of event to listen for
5920 * @param {Function} handler The handler to remove
5921 * @param {Object} scope (optional) The scope (this object) for the handler
5924 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5927 * Starts capture on the specified Observable. All events will be passed
5928 * to the supplied function with the event name + standard signature of the event
5929 * <b>before</b> the event is fired. If the supplied function returns false,
5930 * the event will not fire.
5931 * @param {Observable} o The Observable to capture
5932 * @param {Function} fn The function to call
5933 * @param {Object} scope (optional) The scope (this object) for the fn
5936 Roo.util.Observable.capture = function(o, fn, scope){
5937 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5941 * Removes <b>all</b> added captures from the Observable.
5942 * @param {Observable} o The Observable to release
5945 Roo.util.Observable.releaseCapture = function(o){
5946 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5951 var createBuffered = function(h, o, scope){
5952 var task = new Roo.util.DelayedTask();
5954 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5958 var createSingle = function(h, e, fn, scope){
5960 e.removeListener(fn, scope);
5961 return h.apply(scope, arguments);
5965 var createDelayed = function(h, o, scope){
5967 var args = Array.prototype.slice.call(arguments, 0);
5968 setTimeout(function(){
5969 h.apply(scope, args);
5974 Roo.util.Event = function(obj, name){
5977 this.listeners = [];
5980 Roo.util.Event.prototype = {
5981 addListener : function(fn, scope, options){
5982 var o = options || {};
5983 scope = scope || this.obj;
5984 if(!this.isListening(fn, scope)){
5985 var l = {fn: fn, scope: scope, options: o};
5988 h = createDelayed(h, o, scope);
5991 h = createSingle(h, this, fn, scope);
5994 h = createBuffered(h, o, scope);
5997 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5998 this.listeners.push(l);
6000 this.listeners = this.listeners.slice(0);
6001 this.listeners.push(l);
6006 findListener : function(fn, scope){
6007 scope = scope || this.obj;
6008 var ls = this.listeners;
6009 for(var i = 0, len = ls.length; i < len; i++){
6011 if(l.fn == fn && l.scope == scope){
6018 isListening : function(fn, scope){
6019 return this.findListener(fn, scope) != -1;
6022 removeListener : function(fn, scope){
6024 if((index = this.findListener(fn, scope)) != -1){
6026 this.listeners.splice(index, 1);
6028 this.listeners = this.listeners.slice(0);
6029 this.listeners.splice(index, 1);
6036 clearListeners : function(){
6037 this.listeners = [];
6041 var ls = this.listeners, scope, len = ls.length;
6044 var args = Array.prototype.slice.call(arguments, 0);
6045 for(var i = 0; i < len; i++){
6047 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6048 this.firing = false;
6052 this.firing = false;
6059 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6066 * @class Roo.Document
6067 * @extends Roo.util.Observable
6068 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6070 * @param {Object} config the methods and properties of the 'base' class for the application.
6072 * Generic Page handler - implement this to start your app..
6075 * MyProject = new Roo.Document({
6077 'load' : true // your events..
6080 'ready' : function() {
6081 // fired on Roo.onReady()
6086 Roo.Document = function(cfg) {
6091 Roo.util.Observable.call(this,cfg);
6095 Roo.onReady(function() {
6096 _this.fireEvent('ready');
6102 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6104 * Ext JS Library 1.1.1
6105 * Copyright(c) 2006-2007, Ext JS, LLC.
6107 * Originally Released Under LGPL - original licence link has changed is not relivant.
6110 * <script type="text/javascript">
6114 * @class Roo.EventManager
6115 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6116 * several useful events directly.
6117 * See {@link Roo.EventObject} for more details on normalized event objects.
6120 Roo.EventManager = function(){
6121 var docReadyEvent, docReadyProcId, docReadyState = false;
6122 var resizeEvent, resizeTask, textEvent, textSize;
6123 var E = Roo.lib.Event;
6124 var D = Roo.lib.Dom;
6129 var fireDocReady = function(){
6131 docReadyState = true;
6134 clearInterval(docReadyProcId);
6136 if(Roo.isGecko || Roo.isOpera) {
6137 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6140 var defer = document.getElementById("ie-deferred-loader");
6142 defer.onreadystatechange = null;
6143 defer.parentNode.removeChild(defer);
6147 docReadyEvent.fire();
6148 docReadyEvent.clearListeners();
6153 var initDocReady = function(){
6154 docReadyEvent = new Roo.util.Event();
6155 if(Roo.isGecko || Roo.isOpera) {
6156 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6158 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6159 var defer = document.getElementById("ie-deferred-loader");
6160 defer.onreadystatechange = function(){
6161 if(this.readyState == "complete"){
6165 }else if(Roo.isSafari){
6166 docReadyProcId = setInterval(function(){
6167 var rs = document.readyState;
6168 if(rs == "complete") {
6173 // no matter what, make sure it fires on load
6174 E.on(window, "load", fireDocReady);
6177 var createBuffered = function(h, o){
6178 var task = new Roo.util.DelayedTask(h);
6180 // create new event object impl so new events don't wipe out properties
6181 e = new Roo.EventObjectImpl(e);
6182 task.delay(o.buffer, h, null, [e]);
6186 var createSingle = function(h, el, ename, fn){
6188 Roo.EventManager.removeListener(el, ename, fn);
6193 var createDelayed = function(h, o){
6195 // create new event object impl so new events don't wipe out properties
6196 e = new Roo.EventObjectImpl(e);
6197 setTimeout(function(){
6202 var transitionEndVal = false;
6204 var transitionEnd = function()
6206 if (transitionEndVal) {
6207 return transitionEndVal;
6209 var el = document.createElement('div');
6211 var transEndEventNames = {
6212 WebkitTransition : 'webkitTransitionEnd',
6213 MozTransition : 'transitionend',
6214 OTransition : 'oTransitionEnd otransitionend',
6215 transition : 'transitionend'
6218 for (var name in transEndEventNames) {
6219 if (el.style[name] !== undefined) {
6220 transitionEndVal = transEndEventNames[name];
6221 return transitionEndVal ;
6227 var listen = function(element, ename, opt, fn, scope){
6228 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6229 fn = fn || o.fn; scope = scope || o.scope;
6230 var el = Roo.getDom(element);
6234 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6237 if (ename == 'transitionend') {
6238 ename = transitionEnd();
6240 var h = function(e){
6241 e = Roo.EventObject.setEvent(e);
6244 t = e.getTarget(o.delegate, el);
6251 if(o.stopEvent === true){
6254 if(o.preventDefault === true){
6257 if(o.stopPropagation === true){
6258 e.stopPropagation();
6261 if(o.normalized === false){
6265 fn.call(scope || el, e, t, o);
6268 h = createDelayed(h, o);
6271 h = createSingle(h, el, ename, fn);
6274 h = createBuffered(h, o);
6276 fn._handlers = fn._handlers || [];
6279 fn._handlers.push([Roo.id(el), ename, h]);
6284 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6285 el.addEventListener("DOMMouseScroll", h, false);
6286 E.on(window, 'unload', function(){
6287 el.removeEventListener("DOMMouseScroll", h, false);
6290 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6291 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6296 var stopListening = function(el, ename, fn){
6297 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6299 for(var i = 0, len = hds.length; i < len; i++){
6301 if(h[0] == id && h[1] == ename){
6308 E.un(el, ename, hd);
6309 el = Roo.getDom(el);
6310 if(ename == "mousewheel" && el.addEventListener){
6311 el.removeEventListener("DOMMouseScroll", hd, false);
6313 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6314 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6318 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6325 * @scope Roo.EventManager
6330 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6331 * object with a Roo.EventObject
6332 * @param {Function} fn The method the event invokes
6333 * @param {Object} scope An object that becomes the scope of the handler
6334 * @param {boolean} override If true, the obj passed in becomes
6335 * the execution scope of the listener
6336 * @return {Function} The wrapped function
6339 wrap : function(fn, scope, override){
6341 Roo.EventObject.setEvent(e);
6342 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6347 * Appends an event handler to an element (shorthand for addListener)
6348 * @param {String/HTMLElement} element The html element or id to assign the
6349 * @param {String} eventName The type of event to listen for
6350 * @param {Function} handler The method the event invokes
6351 * @param {Object} scope (optional) The scope in which to execute the handler
6352 * function. The handler function's "this" context.
6353 * @param {Object} options (optional) An object containing handler configuration
6354 * properties. This may contain any of the following properties:<ul>
6355 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6356 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6357 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6358 * <li>preventDefault {Boolean} True to prevent the default action</li>
6359 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6360 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6361 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6362 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6363 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6364 * by the specified number of milliseconds. If the event fires again within that time, the original
6365 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6368 * <b>Combining Options</b><br>
6369 * Using the options argument, it is possible to combine different types of listeners:<br>
6371 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6373 el.on('click', this.onClick, this, {
6380 * <b>Attaching multiple handlers in 1 call</b><br>
6381 * The method also allows for a single argument to be passed which is a config object containing properties
6382 * which specify multiple handlers.
6392 fn: this.onMouseOver
6401 * Or a shorthand syntax:<br>
6404 'click' : this.onClick,
6405 'mouseover' : this.onMouseOver,
6406 'mouseout' : this.onMouseOut
6410 addListener : function(element, eventName, fn, scope, options){
6411 if(typeof eventName == "object"){
6417 if(typeof o[e] == "function"){
6419 listen(element, e, o, o[e], o.scope);
6421 // individual options
6422 listen(element, e, o[e]);
6427 return listen(element, eventName, options, fn, scope);
6431 * Removes an event handler
6433 * @param {String/HTMLElement} element The id or html element to remove the
6435 * @param {String} eventName The type of event
6436 * @param {Function} fn
6437 * @return {Boolean} True if a listener was actually removed
6439 removeListener : function(element, eventName, fn){
6440 return stopListening(element, eventName, fn);
6444 * Fires when the document is ready (before onload and before images are loaded). Can be
6445 * accessed shorthanded Roo.onReady().
6446 * @param {Function} fn The method the event invokes
6447 * @param {Object} scope An object that becomes the scope of the handler
6448 * @param {boolean} options
6450 onDocumentReady : function(fn, scope, options){
6451 if(docReadyState){ // if it already fired
6452 docReadyEvent.addListener(fn, scope, options);
6453 docReadyEvent.fire();
6454 docReadyEvent.clearListeners();
6460 docReadyEvent.addListener(fn, scope, options);
6464 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6465 * @param {Function} fn The method the event invokes
6466 * @param {Object} scope An object that becomes the scope of the handler
6467 * @param {boolean} options
6469 onWindowResize : function(fn, scope, options){
6471 resizeEvent = new Roo.util.Event();
6472 resizeTask = new Roo.util.DelayedTask(function(){
6473 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6475 E.on(window, "resize", function(){
6477 resizeTask.delay(50);
6479 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6483 resizeEvent.addListener(fn, scope, options);
6487 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6488 * @param {Function} fn The method the event invokes
6489 * @param {Object} scope An object that becomes the scope of the handler
6490 * @param {boolean} options
6492 onTextResize : function(fn, scope, options){
6494 textEvent = new Roo.util.Event();
6495 var textEl = new Roo.Element(document.createElement('div'));
6496 textEl.dom.className = 'x-text-resize';
6497 textEl.dom.innerHTML = 'X';
6498 textEl.appendTo(document.body);
6499 textSize = textEl.dom.offsetHeight;
6500 setInterval(function(){
6501 if(textEl.dom.offsetHeight != textSize){
6502 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6504 }, this.textResizeInterval);
6506 textEvent.addListener(fn, scope, options);
6510 * Removes the passed window resize listener.
6511 * @param {Function} fn The method the event invokes
6512 * @param {Object} scope The scope of handler
6514 removeResizeListener : function(fn, scope){
6516 resizeEvent.removeListener(fn, scope);
6521 fireResize : function(){
6523 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6527 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6531 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6533 textResizeInterval : 50
6538 * @scopeAlias pub=Roo.EventManager
6542 * Appends an event handler to an element (shorthand for addListener)
6543 * @param {String/HTMLElement} element The html element or id to assign the
6544 * @param {String} eventName The type of event to listen for
6545 * @param {Function} handler The method the event invokes
6546 * @param {Object} scope (optional) The scope in which to execute the handler
6547 * function. The handler function's "this" context.
6548 * @param {Object} options (optional) An object containing handler configuration
6549 * properties. This may contain any of the following properties:<ul>
6550 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6551 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6552 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6553 * <li>preventDefault {Boolean} True to prevent the default action</li>
6554 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6555 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6556 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6557 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6558 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6559 * by the specified number of milliseconds. If the event fires again within that time, the original
6560 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6563 * <b>Combining Options</b><br>
6564 * Using the options argument, it is possible to combine different types of listeners:<br>
6566 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6568 el.on('click', this.onClick, this, {
6575 * <b>Attaching multiple handlers in 1 call</b><br>
6576 * The method also allows for a single argument to be passed which is a config object containing properties
6577 * which specify multiple handlers.
6587 fn: this.onMouseOver
6596 * Or a shorthand syntax:<br>
6599 'click' : this.onClick,
6600 'mouseover' : this.onMouseOver,
6601 'mouseout' : this.onMouseOut
6605 pub.on = pub.addListener;
6606 pub.un = pub.removeListener;
6608 pub.stoppedMouseDownEvent = new Roo.util.Event();
6612 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6613 * @param {Function} fn The method the event invokes
6614 * @param {Object} scope An object that becomes the scope of the handler
6615 * @param {boolean} override If true, the obj passed in becomes
6616 * the execution scope of the listener
6620 Roo.onReady = Roo.EventManager.onDocumentReady;
6622 Roo.onReady(function(){
6623 var bd = Roo.get(document.body);
6628 : Roo.isGecko ? "roo-gecko"
6629 : Roo.isOpera ? "roo-opera"
6630 : Roo.isSafari ? "roo-safari" : ""];
6633 cls.push("roo-mac");
6636 cls.push("roo-linux");
6639 cls.push("roo-ios");
6642 cls.push("roo-touch");
6644 if(Roo.isBorderBox){
6645 cls.push('roo-border-box');
6647 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6648 var p = bd.dom.parentNode;
6650 p.className += ' roo-strict';
6653 bd.addClass(cls.join(' '));
6657 * @class Roo.EventObject
6658 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6659 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6662 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6664 var target = e.getTarget();
6667 var myDiv = Roo.get("myDiv");
6668 myDiv.on("click", handleClick);
6670 Roo.EventManager.on("myDiv", 'click', handleClick);
6671 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6675 Roo.EventObject = function(){
6677 var E = Roo.lib.Event;
6679 // safari keypress events for special keys return bad keycodes
6682 63235 : 39, // right
6685 63276 : 33, // page up
6686 63277 : 34, // page down
6687 63272 : 46, // delete
6692 // normalize button clicks
6693 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6694 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6696 Roo.EventObjectImpl = function(e){
6698 this.setEvent(e.browserEvent || e);
6701 Roo.EventObjectImpl.prototype = {
6703 * Used to fix doc tools.
6704 * @scope Roo.EventObject.prototype
6710 /** The normal browser event */
6711 browserEvent : null,
6712 /** The button pressed in a mouse event */
6714 /** True if the shift key was down during the event */
6716 /** True if the control key was down during the event */
6718 /** True if the alt key was down during the event */
6777 setEvent : function(e){
6778 if(e == this || (e && e.browserEvent)){ // already wrapped
6781 this.browserEvent = e;
6783 // normalize buttons
6784 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6785 if(e.type == 'click' && this.button == -1){
6789 this.shiftKey = e.shiftKey;
6790 // mac metaKey behaves like ctrlKey
6791 this.ctrlKey = e.ctrlKey || e.metaKey;
6792 this.altKey = e.altKey;
6793 // in getKey these will be normalized for the mac
6794 this.keyCode = e.keyCode;
6795 // keyup warnings on firefox.
6796 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6797 // cache the target for the delayed and or buffered events
6798 this.target = E.getTarget(e);
6800 this.xy = E.getXY(e);
6803 this.shiftKey = false;
6804 this.ctrlKey = false;
6805 this.altKey = false;
6815 * Stop the event (preventDefault and stopPropagation)
6817 stopEvent : function(){
6818 if(this.browserEvent){
6819 if(this.browserEvent.type == 'mousedown'){
6820 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6822 E.stopEvent(this.browserEvent);
6827 * Prevents the browsers default handling of the event.
6829 preventDefault : function(){
6830 if(this.browserEvent){
6831 E.preventDefault(this.browserEvent);
6836 isNavKeyPress : function(){
6837 var k = this.keyCode;
6838 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6839 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6842 isSpecialKey : function(){
6843 var k = this.keyCode;
6844 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6845 (k == 16) || (k == 17) ||
6846 (k >= 18 && k <= 20) ||
6847 (k >= 33 && k <= 35) ||
6848 (k >= 36 && k <= 39) ||
6849 (k >= 44 && k <= 45);
6852 * Cancels bubbling of the event.
6854 stopPropagation : function(){
6855 if(this.browserEvent){
6856 if(this.type == 'mousedown'){
6857 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6859 E.stopPropagation(this.browserEvent);
6864 * Gets the key code for the event.
6867 getCharCode : function(){
6868 return this.charCode || this.keyCode;
6872 * Returns a normalized keyCode for the event.
6873 * @return {Number} The key code
6875 getKey : function(){
6876 var k = this.keyCode || this.charCode;
6877 return Roo.isSafari ? (safariKeys[k] || k) : k;
6881 * Gets the x coordinate of the event.
6884 getPageX : function(){
6889 * Gets the y coordinate of the event.
6892 getPageY : function(){
6897 * Gets the time of the event.
6900 getTime : function(){
6901 if(this.browserEvent){
6902 return E.getTime(this.browserEvent);
6908 * Gets the page coordinates of the event.
6909 * @return {Array} The xy values like [x, y]
6916 * Gets the target for the event.
6917 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6918 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6919 search as a number or element (defaults to 10 || document.body)
6920 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6921 * @return {HTMLelement}
6923 getTarget : function(selector, maxDepth, returnEl){
6924 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6927 * Gets the related target.
6928 * @return {HTMLElement}
6930 getRelatedTarget : function(){
6931 if(this.browserEvent){
6932 return E.getRelatedTarget(this.browserEvent);
6938 * Normalizes mouse wheel delta across browsers
6939 * @return {Number} The delta
6941 getWheelDelta : function(){
6942 var e = this.browserEvent;
6944 if(e.wheelDelta){ /* IE/Opera. */
6945 delta = e.wheelDelta/120;
6946 }else if(e.detail){ /* Mozilla case. */
6947 delta = -e.detail/3;
6953 * Returns true if the control, meta, shift or alt key was pressed during this event.
6956 hasModifier : function(){
6957 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6961 * Returns true if the target of this event equals el or is a child of el
6962 * @param {String/HTMLElement/Element} el
6963 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6966 within : function(el, related){
6967 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6968 return t && Roo.fly(el).contains(t);
6971 getPoint : function(){
6972 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6976 return new Roo.EventObjectImpl();
6981 * Ext JS Library 1.1.1
6982 * Copyright(c) 2006-2007, Ext JS, LLC.
6984 * Originally Released Under LGPL - original licence link has changed is not relivant.
6987 * <script type="text/javascript">
6991 // was in Composite Element!??!?!
6994 var D = Roo.lib.Dom;
6995 var E = Roo.lib.Event;
6996 var A = Roo.lib.Anim;
6998 // local style camelizing for speed
7000 var camelRe = /(-[a-z])/gi;
7001 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7002 var view = document.defaultView;
7005 * @class Roo.Element
7006 * Represents an Element in the DOM.<br><br>
7009 var el = Roo.get("my-div");
7012 var el = getEl("my-div");
7014 // or with a DOM element
7015 var el = Roo.get(myDivElement);
7017 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7018 * each call instead of constructing a new one.<br><br>
7019 * <b>Animations</b><br />
7020 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7021 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7023 Option Default Description
7024 --------- -------- ---------------------------------------------
7025 duration .35 The duration of the animation in seconds
7026 easing easeOut The YUI easing method
7027 callback none A function to execute when the anim completes
7028 scope this The scope (this) of the callback function
7030 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7031 * manipulate the animation. Here's an example:
7033 var el = Roo.get("my-div");
7038 // default animation
7039 el.setWidth(100, true);
7041 // animation with some options set
7048 // using the "anim" property to get the Anim object
7054 el.setWidth(100, opt);
7056 if(opt.anim.isAnimated()){
7060 * <b> Composite (Collections of) Elements</b><br />
7061 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7062 * @constructor Create a new Element directly.
7063 * @param {String/HTMLElement} element
7064 * @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).
7066 Roo.Element = function(element, forceNew){
7067 var dom = typeof element == "string" ?
7068 document.getElementById(element) : element;
7069 if(!dom){ // invalid id/element
7073 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7074 return Roo.Element.cache[id];
7084 * The DOM element ID
7087 this.id = id || Roo.id(dom);
7090 var El = Roo.Element;
7094 * The element's default display mode (defaults to "")
7097 originalDisplay : "",
7101 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7107 * Sets the element's visibility mode. When setVisible() is called it
7108 * will use this to determine whether to set the visibility or the display property.
7109 * @param visMode Element.VISIBILITY or Element.DISPLAY
7110 * @return {Roo.Element} this
7112 setVisibilityMode : function(visMode){
7113 this.visibilityMode = visMode;
7117 * Convenience method for setVisibilityMode(Element.DISPLAY)
7118 * @param {String} display (optional) What to set display to when visible
7119 * @return {Roo.Element} this
7121 enableDisplayMode : function(display){
7122 this.setVisibilityMode(El.DISPLAY);
7123 if(typeof display != "undefined") { this.originalDisplay = display; }
7128 * 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)
7129 * @param {String} selector The simple selector to test
7130 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7131 search as a number or element (defaults to 10 || document.body)
7132 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7133 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7135 findParent : function(simpleSelector, maxDepth, returnEl){
7136 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7137 maxDepth = maxDepth || 50;
7138 if(typeof maxDepth != "number"){
7139 stopEl = Roo.getDom(maxDepth);
7142 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7143 if(dq.is(p, simpleSelector)){
7144 return returnEl ? Roo.get(p) : p;
7154 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7155 * @param {String} selector The simple selector to test
7156 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7157 search as a number or element (defaults to 10 || document.body)
7158 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7159 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7161 findParentNode : function(simpleSelector, maxDepth, returnEl){
7162 var p = Roo.fly(this.dom.parentNode, '_internal');
7163 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7167 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7168 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7169 * @param {String} selector The simple selector to test
7170 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7171 search as a number or element (defaults to 10 || document.body)
7172 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7174 up : function(simpleSelector, maxDepth){
7175 return this.findParentNode(simpleSelector, maxDepth, true);
7181 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7182 * @param {String} selector The simple selector to test
7183 * @return {Boolean} True if this element matches the selector, else false
7185 is : function(simpleSelector){
7186 return Roo.DomQuery.is(this.dom, simpleSelector);
7190 * Perform animation on this element.
7191 * @param {Object} args The YUI animation control args
7192 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7193 * @param {Function} onComplete (optional) Function to call when animation completes
7194 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7195 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7196 * @return {Roo.Element} this
7198 animate : function(args, duration, onComplete, easing, animType){
7199 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7204 * @private Internal animation call
7206 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7207 animType = animType || 'run';
7209 var anim = Roo.lib.Anim[animType](
7211 (opt.duration || defaultDur) || .35,
7212 (opt.easing || defaultEase) || 'easeOut',
7214 Roo.callback(cb, this);
7215 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7223 // private legacy anim prep
7224 preanim : function(a, i){
7225 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7229 * Removes worthless text nodes
7230 * @param {Boolean} forceReclean (optional) By default the element
7231 * keeps track if it has been cleaned already so
7232 * you can call this over and over. However, if you update the element and
7233 * need to force a reclean, you can pass true.
7235 clean : function(forceReclean){
7236 if(this.isCleaned && forceReclean !== true){
7240 var d = this.dom, n = d.firstChild, ni = -1;
7242 var nx = n.nextSibling;
7243 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7250 this.isCleaned = true;
7255 calcOffsetsTo : function(el){
7258 var restorePos = false;
7259 if(el.getStyle('position') == 'static'){
7260 el.position('relative');
7265 while(op && op != d && op.tagName != 'HTML'){
7268 op = op.offsetParent;
7271 el.position('static');
7277 * Scrolls this element into view within the passed container.
7278 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7279 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7280 * @return {Roo.Element} this
7282 scrollIntoView : function(container, hscroll){
7283 var c = Roo.getDom(container) || document.body;
7286 var o = this.calcOffsetsTo(c),
7289 b = t+el.offsetHeight,
7290 r = l+el.offsetWidth;
7292 var ch = c.clientHeight;
7293 var ct = parseInt(c.scrollTop, 10);
7294 var cl = parseInt(c.scrollLeft, 10);
7296 var cr = cl + c.clientWidth;
7304 if(hscroll !== false){
7308 c.scrollLeft = r-c.clientWidth;
7315 scrollChildIntoView : function(child, hscroll){
7316 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7320 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7321 * the new height may not be available immediately.
7322 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7323 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7324 * @param {Function} onComplete (optional) Function to call when animation completes
7325 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7326 * @return {Roo.Element} this
7328 autoHeight : function(animate, duration, onComplete, easing){
7329 var oldHeight = this.getHeight();
7331 this.setHeight(1); // force clipping
7332 setTimeout(function(){
7333 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7335 this.setHeight(height);
7337 if(typeof onComplete == "function"){
7341 this.setHeight(oldHeight); // restore original height
7342 this.setHeight(height, animate, duration, function(){
7344 if(typeof onComplete == "function") { onComplete(); }
7345 }.createDelegate(this), easing);
7347 }.createDelegate(this), 0);
7352 * Returns true if this element is an ancestor of the passed element
7353 * @param {HTMLElement/String} el The element to check
7354 * @return {Boolean} True if this element is an ancestor of el, else false
7356 contains : function(el){
7357 if(!el){return false;}
7358 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7362 * Checks whether the element is currently visible using both visibility and display properties.
7363 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7364 * @return {Boolean} True if the element is currently visible, else false
7366 isVisible : function(deep) {
7367 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7368 if(deep !== true || !vis){
7371 var p = this.dom.parentNode;
7372 while(p && p.tagName.toLowerCase() != "body"){
7373 if(!Roo.fly(p, '_isVisible').isVisible()){
7382 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7383 * @param {String} selector The CSS selector
7384 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7385 * @return {CompositeElement/CompositeElementLite} The composite element
7387 select : function(selector, unique){
7388 return El.select(selector, unique, this.dom);
7392 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7393 * @param {String} selector The CSS selector
7394 * @return {Array} An array of the matched nodes
7396 query : function(selector, unique){
7397 return Roo.DomQuery.select(selector, this.dom);
7401 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7402 * @param {String} selector The CSS selector
7403 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7404 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7406 child : function(selector, returnDom){
7407 var n = Roo.DomQuery.selectNode(selector, this.dom);
7408 return returnDom ? n : Roo.get(n);
7412 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7413 * @param {String} selector The CSS selector
7414 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7415 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7417 down : function(selector, returnDom){
7418 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7419 return returnDom ? n : Roo.get(n);
7423 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7424 * @param {String} group The group the DD object is member of
7425 * @param {Object} config The DD config object
7426 * @param {Object} overrides An object containing methods to override/implement on the DD object
7427 * @return {Roo.dd.DD} The DD object
7429 initDD : function(group, config, overrides){
7430 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7431 return Roo.apply(dd, overrides);
7435 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7436 * @param {String} group The group the DDProxy object is member of
7437 * @param {Object} config The DDProxy config object
7438 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7439 * @return {Roo.dd.DDProxy} The DDProxy object
7441 initDDProxy : function(group, config, overrides){
7442 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7443 return Roo.apply(dd, overrides);
7447 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7448 * @param {String} group The group the DDTarget object is member of
7449 * @param {Object} config The DDTarget config object
7450 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7451 * @return {Roo.dd.DDTarget} The DDTarget object
7453 initDDTarget : function(group, config, overrides){
7454 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7455 return Roo.apply(dd, overrides);
7459 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7460 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7461 * @param {Boolean} visible Whether the element is visible
7462 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7463 * @return {Roo.Element} this
7465 setVisible : function(visible, animate){
7467 if(this.visibilityMode == El.DISPLAY){
7468 this.setDisplayed(visible);
7471 this.dom.style.visibility = visible ? "visible" : "hidden";
7474 // closure for composites
7476 var visMode = this.visibilityMode;
7478 this.setOpacity(.01);
7479 this.setVisible(true);
7481 this.anim({opacity: { to: (visible?1:0) }},
7482 this.preanim(arguments, 1),
7483 null, .35, 'easeIn', function(){
7485 if(visMode == El.DISPLAY){
7486 dom.style.display = "none";
7488 dom.style.visibility = "hidden";
7490 Roo.get(dom).setOpacity(1);
7498 * Returns true if display is not "none"
7501 isDisplayed : function() {
7502 return this.getStyle("display") != "none";
7506 * Toggles the element's visibility or display, depending on visibility mode.
7507 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7508 * @return {Roo.Element} this
7510 toggle : function(animate){
7511 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7516 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7517 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7518 * @return {Roo.Element} this
7520 setDisplayed : function(value) {
7521 if(typeof value == "boolean"){
7522 value = value ? this.originalDisplay : "none";
7524 this.setStyle("display", value);
7529 * Tries to focus the element. Any exceptions are caught and ignored.
7530 * @return {Roo.Element} this
7532 focus : function() {
7540 * Tries to blur the element. Any exceptions are caught and ignored.
7541 * @return {Roo.Element} this
7551 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7552 * @param {String/Array} className The CSS class to add, or an array of classes
7553 * @return {Roo.Element} this
7555 addClass : function(className){
7556 if(className instanceof Array){
7557 for(var i = 0, len = className.length; i < len; i++) {
7558 this.addClass(className[i]);
7561 if(className && !this.hasClass(className)){
7562 this.dom.className = this.dom.className + " " + className;
7569 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7570 * @param {String/Array} className The CSS class to add, or an array of classes
7571 * @return {Roo.Element} this
7573 radioClass : function(className){
7574 var siblings = this.dom.parentNode.childNodes;
7575 for(var i = 0; i < siblings.length; i++) {
7576 var s = siblings[i];
7577 if(s.nodeType == 1){
7578 Roo.get(s).removeClass(className);
7581 this.addClass(className);
7586 * Removes one or more CSS classes from the element.
7587 * @param {String/Array} className The CSS class to remove, or an array of classes
7588 * @return {Roo.Element} this
7590 removeClass : function(className){
7591 if(!className || !this.dom.className){
7594 if(className instanceof Array){
7595 for(var i = 0, len = className.length; i < len; i++) {
7596 this.removeClass(className[i]);
7599 if(this.hasClass(className)){
7600 var re = this.classReCache[className];
7602 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7603 this.classReCache[className] = re;
7605 this.dom.className =
7606 this.dom.className.replace(re, " ");
7616 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7617 * @param {String} className The CSS class to toggle
7618 * @return {Roo.Element} this
7620 toggleClass : function(className){
7621 if(this.hasClass(className)){
7622 this.removeClass(className);
7624 this.addClass(className);
7630 * Checks if the specified CSS class exists on this element's DOM node.
7631 * @param {String} className The CSS class to check for
7632 * @return {Boolean} True if the class exists, else false
7634 hasClass : function(className){
7635 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7639 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7640 * @param {String} oldClassName The CSS class to replace
7641 * @param {String} newClassName The replacement CSS class
7642 * @return {Roo.Element} this
7644 replaceClass : function(oldClassName, newClassName){
7645 this.removeClass(oldClassName);
7646 this.addClass(newClassName);
7651 * Returns an object with properties matching the styles requested.
7652 * For example, el.getStyles('color', 'font-size', 'width') might return
7653 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7654 * @param {String} style1 A style name
7655 * @param {String} style2 A style name
7656 * @param {String} etc.
7657 * @return {Object} The style object
7659 getStyles : function(){
7660 var a = arguments, len = a.length, r = {};
7661 for(var i = 0; i < len; i++){
7662 r[a[i]] = this.getStyle(a[i]);
7668 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7669 * @param {String} property The style property whose value is returned.
7670 * @return {String} The current value of the style property for this element.
7672 getStyle : function(){
7673 return view && view.getComputedStyle ?
7675 var el = this.dom, v, cs, camel;
7676 if(prop == 'float'){
7679 if(el.style && (v = el.style[prop])){
7682 if(cs = view.getComputedStyle(el, "")){
7683 if(!(camel = propCache[prop])){
7684 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7691 var el = this.dom, v, cs, camel;
7692 if(prop == 'opacity'){
7693 if(typeof el.style.filter == 'string'){
7694 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7696 var fv = parseFloat(m[1]);
7698 return fv ? fv / 100 : 0;
7703 }else if(prop == 'float'){
7704 prop = "styleFloat";
7706 if(!(camel = propCache[prop])){
7707 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7709 if(v = el.style[camel]){
7712 if(cs = el.currentStyle){
7720 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7721 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7722 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7723 * @return {Roo.Element} this
7725 setStyle : function(prop, value){
7726 if(typeof prop == "string"){
7728 if (prop == 'float') {
7729 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7734 if(!(camel = propCache[prop])){
7735 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7738 if(camel == 'opacity') {
7739 this.setOpacity(value);
7741 this.dom.style[camel] = value;
7744 for(var style in prop){
7745 if(typeof prop[style] != "function"){
7746 this.setStyle(style, prop[style]);
7754 * More flexible version of {@link #setStyle} for setting style properties.
7755 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7756 * a function which returns such a specification.
7757 * @return {Roo.Element} this
7759 applyStyles : function(style){
7760 Roo.DomHelper.applyStyles(this.dom, style);
7765 * 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).
7766 * @return {Number} The X position of the element
7769 return D.getX(this.dom);
7773 * 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).
7774 * @return {Number} The Y position of the element
7777 return D.getY(this.dom);
7781 * 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).
7782 * @return {Array} The XY position of the element
7785 return D.getXY(this.dom);
7789 * 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).
7790 * @param {Number} The X position of the element
7791 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7792 * @return {Roo.Element} this
7794 setX : function(x, animate){
7796 D.setX(this.dom, x);
7798 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7804 * 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).
7805 * @param {Number} The Y position of the element
7806 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7807 * @return {Roo.Element} this
7809 setY : function(y, animate){
7811 D.setY(this.dom, y);
7813 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7819 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7820 * @param {String} left The left CSS property value
7821 * @return {Roo.Element} this
7823 setLeft : function(left){
7824 this.setStyle("left", this.addUnits(left));
7829 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7830 * @param {String} top The top CSS property value
7831 * @return {Roo.Element} this
7833 setTop : function(top){
7834 this.setStyle("top", this.addUnits(top));
7839 * Sets the element's CSS right style.
7840 * @param {String} right The right CSS property value
7841 * @return {Roo.Element} this
7843 setRight : function(right){
7844 this.setStyle("right", this.addUnits(right));
7849 * Sets the element's CSS bottom style.
7850 * @param {String} bottom The bottom CSS property value
7851 * @return {Roo.Element} this
7853 setBottom : function(bottom){
7854 this.setStyle("bottom", this.addUnits(bottom));
7859 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7860 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7861 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7862 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7863 * @return {Roo.Element} this
7865 setXY : function(pos, animate){
7867 D.setXY(this.dom, pos);
7869 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7875 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7876 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7877 * @param {Number} x X value for new position (coordinates are page-based)
7878 * @param {Number} y Y value for new position (coordinates are page-based)
7879 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7880 * @return {Roo.Element} this
7882 setLocation : function(x, y, animate){
7883 this.setXY([x, y], this.preanim(arguments, 2));
7888 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7889 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7890 * @param {Number} x X value for new position (coordinates are page-based)
7891 * @param {Number} y Y value for new position (coordinates are page-based)
7892 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7893 * @return {Roo.Element} this
7895 moveTo : function(x, y, animate){
7896 this.setXY([x, y], this.preanim(arguments, 2));
7901 * Returns the region of the given element.
7902 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7903 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7905 getRegion : function(){
7906 return D.getRegion(this.dom);
7910 * Returns the offset height of the element
7911 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7912 * @return {Number} The element's height
7914 getHeight : function(contentHeight){
7915 var h = this.dom.offsetHeight || 0;
7916 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7920 * Returns the offset width of the element
7921 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7922 * @return {Number} The element's width
7924 getWidth : function(contentWidth){
7925 var w = this.dom.offsetWidth || 0;
7926 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7930 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7931 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7932 * if a height has not been set using CSS.
7935 getComputedHeight : function(){
7936 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7938 h = parseInt(this.getStyle('height'), 10) || 0;
7939 if(!this.isBorderBox()){
7940 h += this.getFrameWidth('tb');
7947 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7948 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7949 * if a width has not been set using CSS.
7952 getComputedWidth : function(){
7953 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7955 w = parseInt(this.getStyle('width'), 10) || 0;
7956 if(!this.isBorderBox()){
7957 w += this.getFrameWidth('lr');
7964 * Returns the size of the element.
7965 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7966 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7968 getSize : function(contentSize){
7969 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7973 * Returns the width and height of the viewport.
7974 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7976 getViewSize : function(){
7977 var d = this.dom, doc = document, aw = 0, ah = 0;
7978 if(d == doc || d == doc.body){
7979 return {width : D.getViewWidth(), height: D.getViewHeight()};
7982 width : d.clientWidth,
7983 height: d.clientHeight
7989 * Returns the value of the "value" attribute
7990 * @param {Boolean} asNumber true to parse the value as a number
7991 * @return {String/Number}
7993 getValue : function(asNumber){
7994 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7998 adjustWidth : function(width){
7999 if(typeof width == "number"){
8000 if(this.autoBoxAdjust && !this.isBorderBox()){
8001 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8011 adjustHeight : function(height){
8012 if(typeof height == "number"){
8013 if(this.autoBoxAdjust && !this.isBorderBox()){
8014 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8024 * Set the width of the element
8025 * @param {Number} width The new width
8026 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8027 * @return {Roo.Element} this
8029 setWidth : function(width, animate){
8030 width = this.adjustWidth(width);
8032 this.dom.style.width = this.addUnits(width);
8034 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8040 * Set the height of the element
8041 * @param {Number} height The new height
8042 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8043 * @return {Roo.Element} this
8045 setHeight : function(height, animate){
8046 height = this.adjustHeight(height);
8048 this.dom.style.height = this.addUnits(height);
8050 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8056 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8057 * @param {Number} width The new width
8058 * @param {Number} height The new height
8059 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8060 * @return {Roo.Element} this
8062 setSize : function(width, height, animate){
8063 if(typeof width == "object"){ // in case of object from getSize()
8064 height = width.height; width = width.width;
8066 width = this.adjustWidth(width); height = this.adjustHeight(height);
8068 this.dom.style.width = this.addUnits(width);
8069 this.dom.style.height = this.addUnits(height);
8071 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8077 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8078 * @param {Number} x X value for new position (coordinates are page-based)
8079 * @param {Number} y Y value for new position (coordinates are page-based)
8080 * @param {Number} width The new width
8081 * @param {Number} height The new height
8082 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8083 * @return {Roo.Element} this
8085 setBounds : function(x, y, width, height, animate){
8087 this.setSize(width, height);
8088 this.setLocation(x, y);
8090 width = this.adjustWidth(width); height = this.adjustHeight(height);
8091 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8092 this.preanim(arguments, 4), 'motion');
8098 * 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.
8099 * @param {Roo.lib.Region} region The region to fill
8100 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8101 * @return {Roo.Element} this
8103 setRegion : function(region, animate){
8104 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8109 * Appends an event handler
8111 * @param {String} eventName The type of event to append
8112 * @param {Function} fn The method the event invokes
8113 * @param {Object} scope (optional) The scope (this object) of the fn
8114 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8116 addListener : function(eventName, fn, scope, options){
8118 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8123 * Removes an event handler from this element
8124 * @param {String} eventName the type of event to remove
8125 * @param {Function} fn the method the event invokes
8126 * @return {Roo.Element} this
8128 removeListener : function(eventName, fn){
8129 Roo.EventManager.removeListener(this.dom, eventName, fn);
8134 * Removes all previous added listeners from this element
8135 * @return {Roo.Element} this
8137 removeAllListeners : function(){
8138 E.purgeElement(this.dom);
8142 relayEvent : function(eventName, observable){
8143 this.on(eventName, function(e){
8144 observable.fireEvent(eventName, e);
8149 * Set the opacity of the element
8150 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8151 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8152 * @return {Roo.Element} this
8154 setOpacity : function(opacity, animate){
8156 var s = this.dom.style;
8159 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8160 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8162 s.opacity = opacity;
8165 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8171 * Gets the left X coordinate
8172 * @param {Boolean} local True to get the local css position instead of page coordinate
8175 getLeft : function(local){
8179 return parseInt(this.getStyle("left"), 10) || 0;
8184 * Gets the right X coordinate of the element (element X position + element width)
8185 * @param {Boolean} local True to get the local css position instead of page coordinate
8188 getRight : function(local){
8190 return this.getX() + this.getWidth();
8192 return (this.getLeft(true) + this.getWidth()) || 0;
8197 * Gets the top Y coordinate
8198 * @param {Boolean} local True to get the local css position instead of page coordinate
8201 getTop : function(local) {
8205 return parseInt(this.getStyle("top"), 10) || 0;
8210 * Gets the bottom Y coordinate of the element (element Y position + element height)
8211 * @param {Boolean} local True to get the local css position instead of page coordinate
8214 getBottom : function(local){
8216 return this.getY() + this.getHeight();
8218 return (this.getTop(true) + this.getHeight()) || 0;
8223 * Initializes positioning on this element. If a desired position is not passed, it will make the
8224 * the element positioned relative IF it is not already positioned.
8225 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8226 * @param {Number} zIndex (optional) The zIndex to apply
8227 * @param {Number} x (optional) Set the page X position
8228 * @param {Number} y (optional) Set the page Y position
8230 position : function(pos, zIndex, x, y){
8232 if(this.getStyle('position') == 'static'){
8233 this.setStyle('position', 'relative');
8236 this.setStyle("position", pos);
8239 this.setStyle("z-index", zIndex);
8241 if(x !== undefined && y !== undefined){
8243 }else if(x !== undefined){
8245 }else if(y !== undefined){
8251 * Clear positioning back to the default when the document was loaded
8252 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8253 * @return {Roo.Element} this
8255 clearPositioning : function(value){
8263 "position" : "static"
8269 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8270 * snapshot before performing an update and then restoring the element.
8273 getPositioning : function(){
8274 var l = this.getStyle("left");
8275 var t = this.getStyle("top");
8277 "position" : this.getStyle("position"),
8279 "right" : l ? "" : this.getStyle("right"),
8281 "bottom" : t ? "" : this.getStyle("bottom"),
8282 "z-index" : this.getStyle("z-index")
8287 * Gets the width of the border(s) for the specified side(s)
8288 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8289 * passing lr would get the border (l)eft width + the border (r)ight width.
8290 * @return {Number} The width of the sides passed added together
8292 getBorderWidth : function(side){
8293 return this.addStyles(side, El.borders);
8297 * Gets the width of the padding(s) for the specified side(s)
8298 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8299 * passing lr would get the padding (l)eft + the padding (r)ight.
8300 * @return {Number} The padding of the sides passed added together
8302 getPadding : function(side){
8303 return this.addStyles(side, El.paddings);
8307 * Set positioning with an object returned by getPositioning().
8308 * @param {Object} posCfg
8309 * @return {Roo.Element} this
8311 setPositioning : function(pc){
8312 this.applyStyles(pc);
8313 if(pc.right == "auto"){
8314 this.dom.style.right = "";
8316 if(pc.bottom == "auto"){
8317 this.dom.style.bottom = "";
8323 fixDisplay : function(){
8324 if(this.getStyle("display") == "none"){
8325 this.setStyle("visibility", "hidden");
8326 this.setStyle("display", this.originalDisplay); // first try reverting to default
8327 if(this.getStyle("display") == "none"){ // if that fails, default to block
8328 this.setStyle("display", "block");
8334 * Quick set left and top adding default units
8335 * @param {String} left The left CSS property value
8336 * @param {String} top The top CSS property value
8337 * @return {Roo.Element} this
8339 setLeftTop : function(left, top){
8340 this.dom.style.left = this.addUnits(left);
8341 this.dom.style.top = this.addUnits(top);
8346 * Move this element relative to its current position.
8347 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8348 * @param {Number} distance How far to move the element in pixels
8349 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8350 * @return {Roo.Element} this
8352 move : function(direction, distance, animate){
8353 var xy = this.getXY();
8354 direction = direction.toLowerCase();
8358 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8362 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8367 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8372 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8379 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8380 * @return {Roo.Element} this
8383 if(!this.isClipped){
8384 this.isClipped = true;
8385 this.originalClip = {
8386 "o": this.getStyle("overflow"),
8387 "x": this.getStyle("overflow-x"),
8388 "y": this.getStyle("overflow-y")
8390 this.setStyle("overflow", "hidden");
8391 this.setStyle("overflow-x", "hidden");
8392 this.setStyle("overflow-y", "hidden");
8398 * Return clipping (overflow) to original clipping before clip() was called
8399 * @return {Roo.Element} this
8401 unclip : function(){
8403 this.isClipped = false;
8404 var o = this.originalClip;
8405 if(o.o){this.setStyle("overflow", o.o);}
8406 if(o.x){this.setStyle("overflow-x", o.x);}
8407 if(o.y){this.setStyle("overflow-y", o.y);}
8414 * Gets the x,y coordinates specified by the anchor position on the element.
8415 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8416 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8417 * {width: (target width), height: (target height)} (defaults to the element's current size)
8418 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8419 * @return {Array} [x, y] An array containing the element's x and y coordinates
8421 getAnchorXY : function(anchor, local, s){
8422 //Passing a different size is useful for pre-calculating anchors,
8423 //especially for anchored animations that change the el size.
8425 var w, h, vp = false;
8428 if(d == document.body || d == document){
8430 w = D.getViewWidth(); h = D.getViewHeight();
8432 w = this.getWidth(); h = this.getHeight();
8435 w = s.width; h = s.height;
8437 var x = 0, y = 0, r = Math.round;
8438 switch((anchor || "tl").toLowerCase()){
8480 var sc = this.getScroll();
8481 return [x + sc.left, y + sc.top];
8483 //Add the element's offset xy
8484 var o = this.getXY();
8485 return [x+o[0], y+o[1]];
8489 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8490 * supported position values.
8491 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8492 * @param {String} position The position to align to.
8493 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8494 * @return {Array} [x, y]
8496 getAlignToXY : function(el, p, o){
8500 throw "Element.alignTo with an element that doesn't exist";
8502 var c = false; //constrain to viewport
8503 var p1 = "", p2 = "";
8510 }else if(p.indexOf("-") == -1){
8513 p = p.toLowerCase();
8514 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8516 throw "Element.alignTo with an invalid alignment " + p;
8518 p1 = m[1]; p2 = m[2]; c = !!m[3];
8520 //Subtract the aligned el's internal xy from the target's offset xy
8521 //plus custom offset to get the aligned el's new offset xy
8522 var a1 = this.getAnchorXY(p1, true);
8523 var a2 = el.getAnchorXY(p2, false);
8524 var x = a2[0] - a1[0] + o[0];
8525 var y = a2[1] - a1[1] + o[1];
8527 //constrain the aligned el to viewport if necessary
8528 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8529 // 5px of margin for ie
8530 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8532 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8533 //perpendicular to the vp border, allow the aligned el to slide on that border,
8534 //otherwise swap the aligned el to the opposite border of the target.
8535 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8536 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8537 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8538 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8541 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8542 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8544 if((x+w) > dw + scrollX){
8545 x = swapX ? r.left-w : dw+scrollX-w;
8548 x = swapX ? r.right : scrollX;
8550 if((y+h) > dh + scrollY){
8551 y = swapY ? r.top-h : dh+scrollY-h;
8554 y = swapY ? r.bottom : scrollY;
8561 getConstrainToXY : function(){
8562 var os = {top:0, left:0, bottom:0, right: 0};
8564 return function(el, local, offsets, proposedXY){
8566 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8568 var vw, vh, vx = 0, vy = 0;
8569 if(el.dom == document.body || el.dom == document){
8570 vw = Roo.lib.Dom.getViewWidth();
8571 vh = Roo.lib.Dom.getViewHeight();
8573 vw = el.dom.clientWidth;
8574 vh = el.dom.clientHeight;
8576 var vxy = el.getXY();
8582 var s = el.getScroll();
8584 vx += offsets.left + s.left;
8585 vy += offsets.top + s.top;
8587 vw -= offsets.right;
8588 vh -= offsets.bottom;
8593 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8594 var x = xy[0], y = xy[1];
8595 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8597 // only move it if it needs it
8600 // first validate right/bottom
8609 // then make sure top/left isn't negative
8618 return moved ? [x, y] : false;
8623 adjustForConstraints : function(xy, parent, offsets){
8624 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8628 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8629 * document it aligns it to the viewport.
8630 * The position parameter is optional, and can be specified in any one of the following formats:
8632 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8633 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8634 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8635 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8636 * <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
8637 * element's anchor point, and the second value is used as the target's anchor point.</li>
8639 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8640 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8641 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8642 * that specified in order to enforce the viewport constraints.
8643 * Following are all of the supported anchor positions:
8646 ----- -----------------------------
8647 tl The top left corner (default)
8648 t The center of the top edge
8649 tr The top right corner
8650 l The center of the left edge
8651 c In the center of the element
8652 r The center of the right edge
8653 bl The bottom left corner
8654 b The center of the bottom edge
8655 br The bottom right corner
8659 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8660 el.alignTo("other-el");
8662 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8663 el.alignTo("other-el", "tr?");
8665 // align the bottom right corner of el with the center left edge of other-el
8666 el.alignTo("other-el", "br-l?");
8668 // align the center of el with the bottom left corner of other-el and
8669 // adjust the x position by -6 pixels (and the y position by 0)
8670 el.alignTo("other-el", "c-bl", [-6, 0]);
8672 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8673 * @param {String} position The position to align to.
8674 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8675 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8676 * @return {Roo.Element} this
8678 alignTo : function(element, position, offsets, animate){
8679 var xy = this.getAlignToXY(element, position, offsets);
8680 this.setXY(xy, this.preanim(arguments, 3));
8685 * Anchors an element to another element and realigns it when the window is resized.
8686 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8687 * @param {String} position The position to align to.
8688 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8689 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8690 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8691 * is a number, it is used as the buffer delay (defaults to 50ms).
8692 * @param {Function} callback The function to call after the animation finishes
8693 * @return {Roo.Element} this
8695 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8696 var action = function(){
8697 this.alignTo(el, alignment, offsets, animate);
8698 Roo.callback(callback, this);
8700 Roo.EventManager.onWindowResize(action, this);
8701 var tm = typeof monitorScroll;
8702 if(tm != 'undefined'){
8703 Roo.EventManager.on(window, 'scroll', action, this,
8704 {buffer: tm == 'number' ? monitorScroll : 50});
8706 action.call(this); // align immediately
8710 * Clears any opacity settings from this element. Required in some cases for IE.
8711 * @return {Roo.Element} this
8713 clearOpacity : function(){
8714 if (window.ActiveXObject) {
8715 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8716 this.dom.style.filter = "";
8719 this.dom.style.opacity = "";
8720 this.dom.style["-moz-opacity"] = "";
8721 this.dom.style["-khtml-opacity"] = "";
8727 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8728 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8729 * @return {Roo.Element} this
8731 hide : function(animate){
8732 this.setVisible(false, this.preanim(arguments, 0));
8737 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8738 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8739 * @return {Roo.Element} this
8741 show : function(animate){
8742 this.setVisible(true, this.preanim(arguments, 0));
8747 * @private Test if size has a unit, otherwise appends the default
8749 addUnits : function(size){
8750 return Roo.Element.addUnits(size, this.defaultUnit);
8754 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8755 * @return {Roo.Element} this
8757 beginMeasure : function(){
8759 if(el.offsetWidth || el.offsetHeight){
8760 return this; // offsets work already
8763 var p = this.dom, b = document.body; // start with this element
8764 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8765 var pe = Roo.get(p);
8766 if(pe.getStyle('display') == 'none'){
8767 changed.push({el: p, visibility: pe.getStyle("visibility")});
8768 p.style.visibility = "hidden";
8769 p.style.display = "block";
8773 this._measureChanged = changed;
8779 * Restores displays to before beginMeasure was called
8780 * @return {Roo.Element} this
8782 endMeasure : function(){
8783 var changed = this._measureChanged;
8785 for(var i = 0, len = changed.length; i < len; i++) {
8787 r.el.style.visibility = r.visibility;
8788 r.el.style.display = "none";
8790 this._measureChanged = null;
8796 * Update the innerHTML of this element, optionally searching for and processing scripts
8797 * @param {String} html The new HTML
8798 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8799 * @param {Function} callback For async script loading you can be noticed when the update completes
8800 * @return {Roo.Element} this
8802 update : function(html, loadScripts, callback){
8803 if(typeof html == "undefined"){
8806 if(loadScripts !== true){
8807 this.dom.innerHTML = html;
8808 if(typeof callback == "function"){
8816 html += '<span id="' + id + '"></span>';
8818 E.onAvailable(id, function(){
8819 var hd = document.getElementsByTagName("head")[0];
8820 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8821 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8822 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8825 while(match = re.exec(html)){
8826 var attrs = match[1];
8827 var srcMatch = attrs ? attrs.match(srcRe) : false;
8828 if(srcMatch && srcMatch[2]){
8829 var s = document.createElement("script");
8830 s.src = srcMatch[2];
8831 var typeMatch = attrs.match(typeRe);
8832 if(typeMatch && typeMatch[2]){
8833 s.type = typeMatch[2];
8836 }else if(match[2] && match[2].length > 0){
8837 if(window.execScript) {
8838 window.execScript(match[2]);
8846 window.eval(match[2]);
8850 var el = document.getElementById(id);
8851 if(el){el.parentNode.removeChild(el);}
8852 if(typeof callback == "function"){
8856 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8861 * Direct access to the UpdateManager update() method (takes the same parameters).
8862 * @param {String/Function} url The url for this request or a function to call to get the url
8863 * @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}
8864 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8865 * @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.
8866 * @return {Roo.Element} this
8869 var um = this.getUpdateManager();
8870 um.update.apply(um, arguments);
8875 * Gets this element's UpdateManager
8876 * @return {Roo.UpdateManager} The UpdateManager
8878 getUpdateManager : function(){
8879 if(!this.updateManager){
8880 this.updateManager = new Roo.UpdateManager(this);
8882 return this.updateManager;
8886 * Disables text selection for this element (normalized across browsers)
8887 * @return {Roo.Element} this
8889 unselectable : function(){
8890 this.dom.unselectable = "on";
8891 this.swallowEvent("selectstart", true);
8892 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8893 this.addClass("x-unselectable");
8898 * Calculates the x, y to center this element on the screen
8899 * @return {Array} The x, y values [x, y]
8901 getCenterXY : function(){
8902 return this.getAlignToXY(document, 'c-c');
8906 * Centers the Element in either the viewport, or another Element.
8907 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8909 center : function(centerIn){
8910 this.alignTo(centerIn || document, 'c-c');
8915 * Tests various css rules/browsers to determine if this element uses a border box
8918 isBorderBox : function(){
8919 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8923 * Return a box {x, y, width, height} that can be used to set another elements
8924 * size/location to match this element.
8925 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8926 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8927 * @return {Object} box An object in the format {x, y, width, height}
8929 getBox : function(contentBox, local){
8934 var left = parseInt(this.getStyle("left"), 10) || 0;
8935 var top = parseInt(this.getStyle("top"), 10) || 0;
8938 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8940 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8942 var l = this.getBorderWidth("l")+this.getPadding("l");
8943 var r = this.getBorderWidth("r")+this.getPadding("r");
8944 var t = this.getBorderWidth("t")+this.getPadding("t");
8945 var b = this.getBorderWidth("b")+this.getPadding("b");
8946 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)};
8948 bx.right = bx.x + bx.width;
8949 bx.bottom = bx.y + bx.height;
8954 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8955 for more information about the sides.
8956 * @param {String} sides
8959 getFrameWidth : function(sides, onlyContentBox){
8960 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8964 * 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.
8965 * @param {Object} box The box to fill {x, y, width, height}
8966 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8967 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8968 * @return {Roo.Element} this
8970 setBox : function(box, adjust, animate){
8971 var w = box.width, h = box.height;
8972 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8973 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8974 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8976 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8981 * Forces the browser to repaint this element
8982 * @return {Roo.Element} this
8984 repaint : function(){
8986 this.addClass("x-repaint");
8987 setTimeout(function(){
8988 Roo.get(dom).removeClass("x-repaint");
8994 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8995 * then it returns the calculated width of the sides (see getPadding)
8996 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8997 * @return {Object/Number}
8999 getMargins : function(side){
9002 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9003 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9004 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9005 right: parseInt(this.getStyle("margin-right"), 10) || 0
9008 return this.addStyles(side, El.margins);
9013 addStyles : function(sides, styles){
9015 for(var i = 0, len = sides.length; i < len; i++){
9016 v = this.getStyle(styles[sides.charAt(i)]);
9018 w = parseInt(v, 10);
9026 * Creates a proxy element of this element
9027 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9028 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9029 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9030 * @return {Roo.Element} The new proxy element
9032 createProxy : function(config, renderTo, matchBox){
9034 renderTo = Roo.getDom(renderTo);
9036 renderTo = document.body;
9038 config = typeof config == "object" ?
9039 config : {tag : "div", cls: config};
9040 var proxy = Roo.DomHelper.append(renderTo, config, true);
9042 proxy.setBox(this.getBox());
9048 * Puts a mask over this element to disable user interaction. Requires core.css.
9049 * This method can only be applied to elements which accept child nodes.
9050 * @param {String} msg (optional) A message to display in the mask
9051 * @param {String} msgCls (optional) A css class to apply to the msg element
9052 * @return {Element} The mask element
9054 mask : function(msg, msgCls)
9056 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9057 this.setStyle("position", "relative");
9060 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9062 this.addClass("x-masked");
9063 this._mask.setDisplayed(true);
9068 while (dom && dom.style) {
9069 if (!isNaN(parseInt(dom.style.zIndex))) {
9070 z = Math.max(z, parseInt(dom.style.zIndex));
9072 dom = dom.parentNode;
9074 // if we are masking the body - then it hides everything..
9075 if (this.dom == document.body) {
9077 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9078 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9081 if(typeof msg == 'string'){
9083 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9085 var mm = this._maskMsg;
9086 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9087 if (mm.dom.firstChild) { // weird IE issue?
9088 mm.dom.firstChild.innerHTML = msg;
9090 mm.setDisplayed(true);
9092 mm.setStyle('z-index', z + 102);
9094 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9095 this._mask.setHeight(this.getHeight());
9097 this._mask.setStyle('z-index', z + 100);
9103 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9104 * it is cached for reuse.
9106 unmask : function(removeEl){
9108 if(removeEl === true){
9109 this._mask.remove();
9112 this._maskMsg.remove();
9113 delete this._maskMsg;
9116 this._mask.setDisplayed(false);
9118 this._maskMsg.setDisplayed(false);
9122 this.removeClass("x-masked");
9126 * Returns true if this element is masked
9129 isMasked : function(){
9130 return this._mask && this._mask.isVisible();
9134 * Creates an iframe shim for this element to keep selects and other windowed objects from
9136 * @return {Roo.Element} The new shim element
9138 createShim : function(){
9139 var el = document.createElement('iframe');
9140 el.frameBorder = 'no';
9141 el.className = 'roo-shim';
9142 if(Roo.isIE && Roo.isSecure){
9143 el.src = Roo.SSL_SECURE_URL;
9145 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9146 shim.autoBoxAdjust = false;
9151 * Removes this element from the DOM and deletes it from the cache
9153 remove : function(){
9154 if(this.dom.parentNode){
9155 this.dom.parentNode.removeChild(this.dom);
9157 delete El.cache[this.dom.id];
9161 * Sets up event handlers to add and remove a css class when the mouse is over this element
9162 * @param {String} className
9163 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9164 * mouseout events for children elements
9165 * @return {Roo.Element} this
9167 addClassOnOver : function(className, preventFlicker){
9168 this.on("mouseover", function(){
9169 Roo.fly(this, '_internal').addClass(className);
9171 var removeFn = function(e){
9172 if(preventFlicker !== true || !e.within(this, true)){
9173 Roo.fly(this, '_internal').removeClass(className);
9176 this.on("mouseout", removeFn, this.dom);
9181 * Sets up event handlers to add and remove a css class when this element has the focus
9182 * @param {String} className
9183 * @return {Roo.Element} this
9185 addClassOnFocus : function(className){
9186 this.on("focus", function(){
9187 Roo.fly(this, '_internal').addClass(className);
9189 this.on("blur", function(){
9190 Roo.fly(this, '_internal').removeClass(className);
9195 * 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)
9196 * @param {String} className
9197 * @return {Roo.Element} this
9199 addClassOnClick : function(className){
9201 this.on("mousedown", function(){
9202 Roo.fly(dom, '_internal').addClass(className);
9203 var d = Roo.get(document);
9204 var fn = function(){
9205 Roo.fly(dom, '_internal').removeClass(className);
9206 d.removeListener("mouseup", fn);
9208 d.on("mouseup", fn);
9214 * Stops the specified event from bubbling and optionally prevents the default action
9215 * @param {String} eventName
9216 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9217 * @return {Roo.Element} this
9219 swallowEvent : function(eventName, preventDefault){
9220 var fn = function(e){
9221 e.stopPropagation();
9226 if(eventName instanceof Array){
9227 for(var i = 0, len = eventName.length; i < len; i++){
9228 this.on(eventName[i], fn);
9232 this.on(eventName, fn);
9239 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9242 * Sizes this element to its parent element's dimensions performing
9243 * neccessary box adjustments.
9244 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9245 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9246 * @return {Roo.Element} this
9248 fitToParent : function(monitorResize, targetParent) {
9249 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9250 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9251 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9254 var p = Roo.get(targetParent || this.dom.parentNode);
9255 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9256 if (monitorResize === true) {
9257 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9258 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9264 * Gets the next sibling, skipping text nodes
9265 * @return {HTMLElement} The next sibling or null
9267 getNextSibling : function(){
9268 var n = this.dom.nextSibling;
9269 while(n && n.nodeType != 1){
9276 * Gets the previous sibling, skipping text nodes
9277 * @return {HTMLElement} The previous sibling or null
9279 getPrevSibling : function(){
9280 var n = this.dom.previousSibling;
9281 while(n && n.nodeType != 1){
9282 n = n.previousSibling;
9289 * Appends the passed element(s) to this element
9290 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9291 * @return {Roo.Element} this
9293 appendChild: function(el){
9300 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9301 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9302 * automatically generated with the specified attributes.
9303 * @param {HTMLElement} insertBefore (optional) a child element of this element
9304 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9305 * @return {Roo.Element} The new child element
9307 createChild: function(config, insertBefore, returnDom){
9308 config = config || {tag:'div'};
9310 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9312 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9316 * Appends this element to the passed element
9317 * @param {String/HTMLElement/Element} el The new parent element
9318 * @return {Roo.Element} this
9320 appendTo: function(el){
9321 el = Roo.getDom(el);
9322 el.appendChild(this.dom);
9327 * Inserts this element before the passed element in the DOM
9328 * @param {String/HTMLElement/Element} el The element to insert before
9329 * @return {Roo.Element} this
9331 insertBefore: function(el){
9332 el = Roo.getDom(el);
9333 el.parentNode.insertBefore(this.dom, el);
9338 * Inserts this element after the passed element in the DOM
9339 * @param {String/HTMLElement/Element} el The element to insert after
9340 * @return {Roo.Element} this
9342 insertAfter: function(el){
9343 el = Roo.getDom(el);
9344 el.parentNode.insertBefore(this.dom, el.nextSibling);
9349 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9350 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9351 * @return {Roo.Element} The new child
9353 insertFirst: function(el, returnDom){
9355 if(typeof el == 'object' && !el.nodeType){ // dh config
9356 return this.createChild(el, this.dom.firstChild, returnDom);
9358 el = Roo.getDom(el);
9359 this.dom.insertBefore(el, this.dom.firstChild);
9360 return !returnDom ? Roo.get(el) : el;
9365 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9366 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9367 * @param {String} where (optional) 'before' or 'after' defaults to before
9368 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9369 * @return {Roo.Element} the inserted Element
9371 insertSibling: function(el, where, returnDom){
9372 where = where ? where.toLowerCase() : 'before';
9374 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9376 if(typeof el == 'object' && !el.nodeType){ // dh config
9377 if(where == 'after' && !this.dom.nextSibling){
9378 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9380 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9384 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9385 where == 'before' ? this.dom : this.dom.nextSibling);
9394 * Creates and wraps this element with another element
9395 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9396 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9397 * @return {HTMLElement/Element} The newly created wrapper element
9399 wrap: function(config, returnDom){
9401 config = {tag: "div"};
9403 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9404 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9409 * Replaces the passed element with this element
9410 * @param {String/HTMLElement/Element} el The element to replace
9411 * @return {Roo.Element} this
9413 replace: function(el){
9415 this.insertBefore(el);
9421 * Inserts an html fragment into this element
9422 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9423 * @param {String} html The HTML fragment
9424 * @param {Boolean} returnEl True to return an Roo.Element
9425 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9427 insertHtml : function(where, html, returnEl){
9428 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9429 return returnEl ? Roo.get(el) : el;
9433 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9434 * @param {Object} o The object with the attributes
9435 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9436 * @return {Roo.Element} this
9438 set : function(o, useSet){
9440 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9442 if(attr == "style" || typeof o[attr] == "function") { continue; }
9444 el.className = o["cls"];
9447 el.setAttribute(attr, o[attr]);
9454 Roo.DomHelper.applyStyles(el, o.style);
9460 * Convenience method for constructing a KeyMap
9461 * @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:
9462 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9463 * @param {Function} fn The function to call
9464 * @param {Object} scope (optional) The scope of the function
9465 * @return {Roo.KeyMap} The KeyMap created
9467 addKeyListener : function(key, fn, scope){
9469 if(typeof key != "object" || key instanceof Array){
9485 return new Roo.KeyMap(this, config);
9489 * Creates a KeyMap for this element
9490 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9491 * @return {Roo.KeyMap} The KeyMap created
9493 addKeyMap : function(config){
9494 return new Roo.KeyMap(this, config);
9498 * Returns true if this element is scrollable.
9501 isScrollable : function(){
9503 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9507 * 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().
9508 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9509 * @param {Number} value The new scroll value
9510 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9511 * @return {Element} this
9514 scrollTo : function(side, value, animate){
9515 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9517 this.dom[prop] = value;
9519 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9520 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9526 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9527 * within this element's scrollable range.
9528 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9529 * @param {Number} distance How far to scroll the element in pixels
9530 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9531 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9532 * was scrolled as far as it could go.
9534 scroll : function(direction, distance, animate){
9535 if(!this.isScrollable()){
9539 var l = el.scrollLeft, t = el.scrollTop;
9540 var w = el.scrollWidth, h = el.scrollHeight;
9541 var cw = el.clientWidth, ch = el.clientHeight;
9542 direction = direction.toLowerCase();
9543 var scrolled = false;
9544 var a = this.preanim(arguments, 2);
9549 var v = Math.min(l + distance, w-cw);
9550 this.scrollTo("left", v, a);
9557 var v = Math.max(l - distance, 0);
9558 this.scrollTo("left", v, a);
9566 var v = Math.max(t - distance, 0);
9567 this.scrollTo("top", v, a);
9575 var v = Math.min(t + distance, h-ch);
9576 this.scrollTo("top", v, a);
9585 * Translates the passed page coordinates into left/top css values for this element
9586 * @param {Number/Array} x The page x or an array containing [x, y]
9587 * @param {Number} y The page y
9588 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9590 translatePoints : function(x, y){
9591 if(typeof x == 'object' || x instanceof Array){
9594 var p = this.getStyle('position');
9595 var o = this.getXY();
9597 var l = parseInt(this.getStyle('left'), 10);
9598 var t = parseInt(this.getStyle('top'), 10);
9601 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9604 t = (p == "relative") ? 0 : this.dom.offsetTop;
9607 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9611 * Returns the current scroll position of the element.
9612 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9614 getScroll : function(){
9615 var d = this.dom, doc = document;
9616 if(d == doc || d == doc.body){
9617 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9618 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9619 return {left: l, top: t};
9621 return {left: d.scrollLeft, top: d.scrollTop};
9626 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9627 * are convert to standard 6 digit hex color.
9628 * @param {String} attr The css attribute
9629 * @param {String} defaultValue The default value to use when a valid color isn't found
9630 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9633 getColor : function(attr, defaultValue, prefix){
9634 var v = this.getStyle(attr);
9635 if(!v || v == "transparent" || v == "inherit") {
9636 return defaultValue;
9638 var color = typeof prefix == "undefined" ? "#" : prefix;
9639 if(v.substr(0, 4) == "rgb("){
9640 var rvs = v.slice(4, v.length -1).split(",");
9641 for(var i = 0; i < 3; i++){
9642 var h = parseInt(rvs[i]).toString(16);
9649 if(v.substr(0, 1) == "#"){
9651 for(var i = 1; i < 4; i++){
9652 var c = v.charAt(i);
9655 }else if(v.length == 7){
9656 color += v.substr(1);
9660 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9664 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9665 * gradient background, rounded corners and a 4-way shadow.
9666 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9667 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9668 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9669 * @return {Roo.Element} this
9671 boxWrap : function(cls){
9672 cls = cls || 'x-box';
9673 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9674 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9679 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9680 * @param {String} namespace The namespace in which to look for the attribute
9681 * @param {String} name The attribute name
9682 * @return {String} The attribute value
9684 getAttributeNS : Roo.isIE ? function(ns, name){
9686 var type = typeof d[ns+":"+name];
9687 if(type != 'undefined' && type != 'unknown'){
9688 return d[ns+":"+name];
9691 } : function(ns, name){
9693 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9698 * Sets or Returns the value the dom attribute value
9699 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9700 * @param {String} value (optional) The value to set the attribute to
9701 * @return {String} The attribute value
9703 attr : function(name){
9704 if (arguments.length > 1) {
9705 this.dom.setAttribute(name, arguments[1]);
9706 return arguments[1];
9708 if (typeof(name) == 'object') {
9709 for(var i in name) {
9710 this.attr(i, name[i]);
9716 if (!this.dom.hasAttribute(name)) {
9719 return this.dom.getAttribute(name);
9726 var ep = El.prototype;
9729 * Appends an event handler (Shorthand for addListener)
9730 * @param {String} eventName The type of event to append
9731 * @param {Function} fn The method the event invokes
9732 * @param {Object} scope (optional) The scope (this object) of the fn
9733 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9736 ep.on = ep.addListener;
9738 ep.mon = ep.addListener;
9741 * Removes an event handler from this element (shorthand for removeListener)
9742 * @param {String} eventName the type of event to remove
9743 * @param {Function} fn the method the event invokes
9744 * @return {Roo.Element} this
9747 ep.un = ep.removeListener;
9750 * true to automatically adjust width and height settings for box-model issues (default to true)
9752 ep.autoBoxAdjust = true;
9755 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9758 El.addUnits = function(v, defaultUnit){
9759 if(v === "" || v == "auto"){
9762 if(v === undefined){
9765 if(typeof v == "number" || !El.unitPattern.test(v)){
9766 return v + (defaultUnit || 'px');
9771 // special markup used throughout Roo when box wrapping elements
9772 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>';
9774 * Visibility mode constant - Use visibility to hide element
9780 * Visibility mode constant - Use display to hide element
9786 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9787 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9788 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9800 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9801 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9802 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9803 * @return {Element} The Element object
9806 El.get = function(el){
9808 if(!el){ return null; }
9809 if(typeof el == "string"){ // element id
9810 if(!(elm = document.getElementById(el))){
9813 if(ex = El.cache[el]){
9816 ex = El.cache[el] = new El(elm);
9819 }else if(el.tagName){ // dom element
9823 if(ex = El.cache[id]){
9826 ex = El.cache[id] = new El(el);
9829 }else if(el instanceof El){
9831 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9832 // catch case where it hasn't been appended
9833 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9836 }else if(el.isComposite){
9838 }else if(el instanceof Array){
9839 return El.select(el);
9840 }else if(el == document){
9841 // create a bogus element object representing the document object
9843 var f = function(){};
9844 f.prototype = El.prototype;
9846 docEl.dom = document;
9854 El.uncache = function(el){
9855 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9857 delete El.cache[a[i].id || a[i]];
9863 // Garbage collection - uncache elements/purge listeners on orphaned elements
9864 // so we don't hold a reference and cause the browser to retain them
9865 El.garbageCollect = function(){
9866 if(!Roo.enableGarbageCollector){
9867 clearInterval(El.collectorThread);
9870 for(var eid in El.cache){
9871 var el = El.cache[eid], d = el.dom;
9872 // -------------------------------------------------------
9873 // Determining what is garbage:
9874 // -------------------------------------------------------
9876 // dom node is null, definitely garbage
9877 // -------------------------------------------------------
9879 // no parentNode == direct orphan, definitely garbage
9880 // -------------------------------------------------------
9881 // !d.offsetParent && !document.getElementById(eid)
9882 // display none elements have no offsetParent so we will
9883 // also try to look it up by it's id. However, check
9884 // offsetParent first so we don't do unneeded lookups.
9885 // This enables collection of elements that are not orphans
9886 // directly, but somewhere up the line they have an orphan
9888 // -------------------------------------------------------
9889 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9890 delete El.cache[eid];
9891 if(d && Roo.enableListenerCollection){
9897 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9901 El.Flyweight = function(dom){
9904 El.Flyweight.prototype = El.prototype;
9906 El._flyweights = {};
9908 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9909 * the dom node can be overwritten by other code.
9910 * @param {String/HTMLElement} el The dom node or id
9911 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9912 * prevent conflicts (e.g. internally Roo uses "_internal")
9914 * @return {Element} The shared Element object
9916 El.fly = function(el, named){
9917 named = named || '_global';
9918 el = Roo.getDom(el);
9922 if(!El._flyweights[named]){
9923 El._flyweights[named] = new El.Flyweight();
9925 El._flyweights[named].dom = el;
9926 return El._flyweights[named];
9930 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9931 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9932 * Shorthand of {@link Roo.Element#get}
9933 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9934 * @return {Element} The Element object
9940 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9941 * the dom node can be overwritten by other code.
9942 * Shorthand of {@link Roo.Element#fly}
9943 * @param {String/HTMLElement} el The dom node or id
9944 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9945 * prevent conflicts (e.g. internally Roo uses "_internal")
9947 * @return {Element} The shared Element object
9953 // speedy lookup for elements never to box adjust
9954 var noBoxAdjust = Roo.isStrict ? {
9957 input:1, select:1, textarea:1
9959 if(Roo.isIE || Roo.isGecko){
9960 noBoxAdjust['button'] = 1;
9964 Roo.EventManager.on(window, 'unload', function(){
9966 delete El._flyweights;
9974 Roo.Element.selectorFunction = Roo.DomQuery.select;
9977 Roo.Element.select = function(selector, unique, root){
9979 if(typeof selector == "string"){
9980 els = Roo.Element.selectorFunction(selector, root);
9981 }else if(selector.length !== undefined){
9984 throw "Invalid selector";
9986 if(unique === true){
9987 return new Roo.CompositeElement(els);
9989 return new Roo.CompositeElementLite(els);
9993 * Selects elements based on the passed CSS selector to enable working on them as 1.
9994 * @param {String/Array} selector The CSS selector or an array of elements
9995 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9996 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9997 * @return {CompositeElementLite/CompositeElement}
10001 Roo.select = Roo.Element.select;
10018 * Ext JS Library 1.1.1
10019 * Copyright(c) 2006-2007, Ext JS, LLC.
10021 * Originally Released Under LGPL - original licence link has changed is not relivant.
10024 * <script type="text/javascript">
10029 //Notifies Element that fx methods are available
10030 Roo.enableFx = true;
10034 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10035 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10036 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10037 * Element effects to work.</p><br/>
10039 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10040 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10041 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10042 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10043 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10044 * expected results and should be done with care.</p><br/>
10046 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10047 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10050 ----- -----------------------------
10051 tl The top left corner
10052 t The center of the top edge
10053 tr The top right corner
10054 l The center of the left edge
10055 r The center of the right edge
10056 bl The bottom left corner
10057 b The center of the bottom edge
10058 br The bottom right corner
10060 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10061 * below are common options that can be passed to any Fx method.</b>
10062 * @cfg {Function} callback A function called when the effect is finished
10063 * @cfg {Object} scope The scope of the effect function
10064 * @cfg {String} easing A valid Easing value for the effect
10065 * @cfg {String} afterCls A css class to apply after the effect
10066 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10067 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10068 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10069 * effects that end with the element being visually hidden, ignored otherwise)
10070 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10071 * a function which returns such a specification that will be applied to the Element after the effect finishes
10072 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10073 * @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
10074 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10078 * Slides the element into view. An anchor point can be optionally passed to set the point of
10079 * origin for the slide effect. This function automatically handles wrapping the element with
10080 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10083 // default: slide the element in from the top
10086 // custom: slide the element in from the right with a 2-second duration
10087 el.slideIn('r', { duration: 2 });
10089 // common config options shown with default values
10095 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10096 * @param {Object} options (optional) Object literal with any of the Fx config options
10097 * @return {Roo.Element} The Element
10099 slideIn : function(anchor, o){
10100 var el = this.getFxEl();
10103 el.queueFx(o, function(){
10105 anchor = anchor || "t";
10107 // fix display to visibility
10110 // restore values after effect
10111 var r = this.getFxRestore();
10112 var b = this.getBox();
10113 // fixed size for slide
10117 var wrap = this.fxWrap(r.pos, o, "hidden");
10119 var st = this.dom.style;
10120 st.visibility = "visible";
10121 st.position = "absolute";
10123 // clear out temp styles after slide and unwrap
10124 var after = function(){
10125 el.fxUnwrap(wrap, r.pos, o);
10126 st.width = r.width;
10127 st.height = r.height;
10130 // time to calc the positions
10131 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10133 switch(anchor.toLowerCase()){
10135 wrap.setSize(b.width, 0);
10136 st.left = st.bottom = "0";
10140 wrap.setSize(0, b.height);
10141 st.right = st.top = "0";
10145 wrap.setSize(0, b.height);
10146 wrap.setX(b.right);
10147 st.left = st.top = "0";
10148 a = {width: bw, points: pt};
10151 wrap.setSize(b.width, 0);
10152 wrap.setY(b.bottom);
10153 st.left = st.top = "0";
10154 a = {height: bh, points: pt};
10157 wrap.setSize(0, 0);
10158 st.right = st.bottom = "0";
10159 a = {width: bw, height: bh};
10162 wrap.setSize(0, 0);
10163 wrap.setY(b.y+b.height);
10164 st.right = st.top = "0";
10165 a = {width: bw, height: bh, points: pt};
10168 wrap.setSize(0, 0);
10169 wrap.setXY([b.right, b.bottom]);
10170 st.left = st.top = "0";
10171 a = {width: bw, height: bh, points: pt};
10174 wrap.setSize(0, 0);
10175 wrap.setX(b.x+b.width);
10176 st.left = st.bottom = "0";
10177 a = {width: bw, height: bh, points: pt};
10180 this.dom.style.visibility = "visible";
10183 arguments.callee.anim = wrap.fxanim(a,
10193 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10194 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10195 * 'hidden') but block elements will still take up space in the document. The element must be removed
10196 * from the DOM using the 'remove' config option if desired. This function automatically handles
10197 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10200 // default: slide the element out to the top
10203 // custom: slide the element out to the right with a 2-second duration
10204 el.slideOut('r', { duration: 2 });
10206 // common config options shown with default values
10214 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10215 * @param {Object} options (optional) Object literal with any of the Fx config options
10216 * @return {Roo.Element} The Element
10218 slideOut : function(anchor, o){
10219 var el = this.getFxEl();
10222 el.queueFx(o, function(){
10224 anchor = anchor || "t";
10226 // restore values after effect
10227 var r = this.getFxRestore();
10229 var b = this.getBox();
10230 // fixed size for slide
10234 var wrap = this.fxWrap(r.pos, o, "visible");
10236 var st = this.dom.style;
10237 st.visibility = "visible";
10238 st.position = "absolute";
10242 var after = function(){
10244 el.setDisplayed(false);
10249 el.fxUnwrap(wrap, r.pos, o);
10251 st.width = r.width;
10252 st.height = r.height;
10257 var a, zero = {to: 0};
10258 switch(anchor.toLowerCase()){
10260 st.left = st.bottom = "0";
10261 a = {height: zero};
10264 st.right = st.top = "0";
10268 st.left = st.top = "0";
10269 a = {width: zero, points: {to:[b.right, b.y]}};
10272 st.left = st.top = "0";
10273 a = {height: zero, points: {to:[b.x, b.bottom]}};
10276 st.right = st.bottom = "0";
10277 a = {width: zero, height: zero};
10280 st.right = st.top = "0";
10281 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10284 st.left = st.top = "0";
10285 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10288 st.left = st.bottom = "0";
10289 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10293 arguments.callee.anim = wrap.fxanim(a,
10303 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10304 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10305 * The element must be removed from the DOM using the 'remove' config option if desired.
10311 // common config options shown with default values
10319 * @param {Object} options (optional) Object literal with any of the Fx config options
10320 * @return {Roo.Element} The Element
10322 puff : function(o){
10323 var el = this.getFxEl();
10326 el.queueFx(o, function(){
10327 this.clearOpacity();
10330 // restore values after effect
10331 var r = this.getFxRestore();
10332 var st = this.dom.style;
10334 var after = function(){
10336 el.setDisplayed(false);
10343 el.setPositioning(r.pos);
10344 st.width = r.width;
10345 st.height = r.height;
10350 var width = this.getWidth();
10351 var height = this.getHeight();
10353 arguments.callee.anim = this.fxanim({
10354 width : {to: this.adjustWidth(width * 2)},
10355 height : {to: this.adjustHeight(height * 2)},
10356 points : {by: [-(width * .5), -(height * .5)]},
10358 fontSize: {to:200, unit: "%"}
10369 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10370 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10371 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10377 // all config options shown with default values
10385 * @param {Object} options (optional) Object literal with any of the Fx config options
10386 * @return {Roo.Element} The Element
10388 switchOff : function(o){
10389 var el = this.getFxEl();
10392 el.queueFx(o, function(){
10393 this.clearOpacity();
10396 // restore values after effect
10397 var r = this.getFxRestore();
10398 var st = this.dom.style;
10400 var after = function(){
10402 el.setDisplayed(false);
10408 el.setPositioning(r.pos);
10409 st.width = r.width;
10410 st.height = r.height;
10415 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10416 this.clearOpacity();
10420 points:{by:[0, this.getHeight() * .5]}
10421 }, o, 'motion', 0.3, 'easeIn', after);
10422 }).defer(100, this);
10429 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10430 * changed using the "attr" config option) and then fading back to the original color. If no original
10431 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10434 // default: highlight background to yellow
10437 // custom: highlight foreground text to blue for 2 seconds
10438 el.highlight("0000ff", { attr: 'color', duration: 2 });
10440 // common config options shown with default values
10441 el.highlight("ffff9c", {
10442 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10443 endColor: (current color) or "ffffff",
10448 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10449 * @param {Object} options (optional) Object literal with any of the Fx config options
10450 * @return {Roo.Element} The Element
10452 highlight : function(color, o){
10453 var el = this.getFxEl();
10456 el.queueFx(o, function(){
10457 color = color || "ffff9c";
10458 attr = o.attr || "backgroundColor";
10460 this.clearOpacity();
10463 var origColor = this.getColor(attr);
10464 var restoreColor = this.dom.style[attr];
10465 endColor = (o.endColor || origColor) || "ffffff";
10467 var after = function(){
10468 el.dom.style[attr] = restoreColor;
10473 a[attr] = {from: color, to: endColor};
10474 arguments.callee.anim = this.fxanim(a,
10484 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10487 // default: a single light blue ripple
10490 // custom: 3 red ripples lasting 3 seconds total
10491 el.frame("ff0000", 3, { duration: 3 });
10493 // common config options shown with default values
10494 el.frame("C3DAF9", 1, {
10495 duration: 1 //duration of entire animation (not each individual ripple)
10496 // Note: Easing is not configurable and will be ignored if included
10499 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10500 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10501 * @param {Object} options (optional) Object literal with any of the Fx config options
10502 * @return {Roo.Element} The Element
10504 frame : function(color, count, o){
10505 var el = this.getFxEl();
10508 el.queueFx(o, function(){
10509 color = color || "#C3DAF9";
10510 if(color.length == 6){
10511 color = "#" + color;
10513 count = count || 1;
10514 duration = o.duration || 1;
10517 var b = this.getBox();
10518 var animFn = function(){
10519 var proxy = this.createProxy({
10522 visbility:"hidden",
10523 position:"absolute",
10524 "z-index":"35000", // yee haw
10525 border:"0px solid " + color
10528 var scale = Roo.isBorderBox ? 2 : 1;
10530 top:{from:b.y, to:b.y - 20},
10531 left:{from:b.x, to:b.x - 20},
10532 borderWidth:{from:0, to:10},
10533 opacity:{from:1, to:0},
10534 height:{from:b.height, to:(b.height + (20*scale))},
10535 width:{from:b.width, to:(b.width + (20*scale))}
10536 }, duration, function(){
10540 animFn.defer((duration/2)*1000, this);
10551 * Creates a pause before any subsequent queued effects begin. If there are
10552 * no effects queued after the pause it will have no effect.
10557 * @param {Number} seconds The length of time to pause (in seconds)
10558 * @return {Roo.Element} The Element
10560 pause : function(seconds){
10561 var el = this.getFxEl();
10564 el.queueFx(o, function(){
10565 setTimeout(function(){
10567 }, seconds * 1000);
10573 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10574 * using the "endOpacity" config option.
10577 // default: fade in from opacity 0 to 100%
10580 // custom: fade in from opacity 0 to 75% over 2 seconds
10581 el.fadeIn({ endOpacity: .75, duration: 2});
10583 // common config options shown with default values
10585 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10590 * @param {Object} options (optional) Object literal with any of the Fx config options
10591 * @return {Roo.Element} The Element
10593 fadeIn : function(o){
10594 var el = this.getFxEl();
10596 el.queueFx(o, function(){
10597 this.setOpacity(0);
10599 this.dom.style.visibility = 'visible';
10600 var to = o.endOpacity || 1;
10601 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10602 o, null, .5, "easeOut", function(){
10604 this.clearOpacity();
10613 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10614 * using the "endOpacity" config option.
10617 // default: fade out from the element's current opacity to 0
10620 // custom: fade out from the element's current opacity to 25% over 2 seconds
10621 el.fadeOut({ endOpacity: .25, duration: 2});
10623 // common config options shown with default values
10625 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10632 * @param {Object} options (optional) Object literal with any of the Fx config options
10633 * @return {Roo.Element} The Element
10635 fadeOut : function(o){
10636 var el = this.getFxEl();
10638 el.queueFx(o, function(){
10639 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10640 o, null, .5, "easeOut", function(){
10641 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10642 this.dom.style.display = "none";
10644 this.dom.style.visibility = "hidden";
10646 this.clearOpacity();
10654 * Animates the transition of an element's dimensions from a starting height/width
10655 * to an ending height/width.
10658 // change height and width to 100x100 pixels
10659 el.scale(100, 100);
10661 // common config options shown with default values. The height and width will default to
10662 // the element's existing values if passed as null.
10665 [element's height], {
10670 * @param {Number} width The new width (pass undefined to keep the original width)
10671 * @param {Number} height The new height (pass undefined to keep the original height)
10672 * @param {Object} options (optional) Object literal with any of the Fx config options
10673 * @return {Roo.Element} The Element
10675 scale : function(w, h, o){
10676 this.shift(Roo.apply({}, o, {
10684 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10685 * Any of these properties not specified in the config object will not be changed. This effect
10686 * requires that at least one new dimension, position or opacity setting must be passed in on
10687 * the config object in order for the function to have any effect.
10690 // slide the element horizontally to x position 200 while changing the height and opacity
10691 el.shift({ x: 200, height: 50, opacity: .8 });
10693 // common config options shown with default values.
10695 width: [element's width],
10696 height: [element's height],
10697 x: [element's x position],
10698 y: [element's y position],
10699 opacity: [element's opacity],
10704 * @param {Object} options Object literal with any of the Fx config options
10705 * @return {Roo.Element} The Element
10707 shift : function(o){
10708 var el = this.getFxEl();
10710 el.queueFx(o, function(){
10711 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10712 if(w !== undefined){
10713 a.width = {to: this.adjustWidth(w)};
10715 if(h !== undefined){
10716 a.height = {to: this.adjustHeight(h)};
10718 if(x !== undefined || y !== undefined){
10720 x !== undefined ? x : this.getX(),
10721 y !== undefined ? y : this.getY()
10724 if(op !== undefined){
10725 a.opacity = {to: op};
10727 if(o.xy !== undefined){
10728 a.points = {to: o.xy};
10730 arguments.callee.anim = this.fxanim(a,
10731 o, 'motion', .35, "easeOut", function(){
10739 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10740 * ending point of the effect.
10743 // default: slide the element downward while fading out
10746 // custom: slide the element out to the right with a 2-second duration
10747 el.ghost('r', { duration: 2 });
10749 // common config options shown with default values
10757 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10758 * @param {Object} options (optional) Object literal with any of the Fx config options
10759 * @return {Roo.Element} The Element
10761 ghost : function(anchor, o){
10762 var el = this.getFxEl();
10765 el.queueFx(o, function(){
10766 anchor = anchor || "b";
10768 // restore values after effect
10769 var r = this.getFxRestore();
10770 var w = this.getWidth(),
10771 h = this.getHeight();
10773 var st = this.dom.style;
10775 var after = function(){
10777 el.setDisplayed(false);
10783 el.setPositioning(r.pos);
10784 st.width = r.width;
10785 st.height = r.height;
10790 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10791 switch(anchor.toLowerCase()){
10818 arguments.callee.anim = this.fxanim(a,
10828 * Ensures that all effects queued after syncFx is called on the element are
10829 * run concurrently. This is the opposite of {@link #sequenceFx}.
10830 * @return {Roo.Element} The Element
10832 syncFx : function(){
10833 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10842 * Ensures that all effects queued after sequenceFx is called on the element are
10843 * run in sequence. This is the opposite of {@link #syncFx}.
10844 * @return {Roo.Element} The Element
10846 sequenceFx : function(){
10847 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10849 concurrent : false,
10856 nextFx : function(){
10857 var ef = this.fxQueue[0];
10864 * Returns true if the element has any effects actively running or queued, else returns false.
10865 * @return {Boolean} True if element has active effects, else false
10867 hasActiveFx : function(){
10868 return this.fxQueue && this.fxQueue[0];
10872 * Stops any running effects and clears the element's internal effects queue if it contains
10873 * any additional effects that haven't started yet.
10874 * @return {Roo.Element} The Element
10876 stopFx : function(){
10877 if(this.hasActiveFx()){
10878 var cur = this.fxQueue[0];
10879 if(cur && cur.anim && cur.anim.isAnimated()){
10880 this.fxQueue = [cur]; // clear out others
10881 cur.anim.stop(true);
10888 beforeFx : function(o){
10889 if(this.hasActiveFx() && !o.concurrent){
10900 * Returns true if the element is currently blocking so that no other effect can be queued
10901 * until this effect is finished, else returns false if blocking is not set. This is commonly
10902 * used to ensure that an effect initiated by a user action runs to completion prior to the
10903 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10904 * @return {Boolean} True if blocking, else false
10906 hasFxBlock : function(){
10907 var q = this.fxQueue;
10908 return q && q[0] && q[0].block;
10912 queueFx : function(o, fn){
10916 if(!this.hasFxBlock()){
10917 Roo.applyIf(o, this.fxDefaults);
10919 var run = this.beforeFx(o);
10920 fn.block = o.block;
10921 this.fxQueue.push(fn);
10933 fxWrap : function(pos, o, vis){
10935 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10938 wrapXY = this.getXY();
10940 var div = document.createElement("div");
10941 div.style.visibility = vis;
10942 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10943 wrap.setPositioning(pos);
10944 if(wrap.getStyle("position") == "static"){
10945 wrap.position("relative");
10947 this.clearPositioning('auto');
10949 wrap.dom.appendChild(this.dom);
10951 wrap.setXY(wrapXY);
10958 fxUnwrap : function(wrap, pos, o){
10959 this.clearPositioning();
10960 this.setPositioning(pos);
10962 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10968 getFxRestore : function(){
10969 var st = this.dom.style;
10970 return {pos: this.getPositioning(), width: st.width, height : st.height};
10974 afterFx : function(o){
10976 this.applyStyles(o.afterStyle);
10979 this.addClass(o.afterCls);
10981 if(o.remove === true){
10984 Roo.callback(o.callback, o.scope, [this]);
10986 this.fxQueue.shift();
10992 getFxEl : function(){ // support for composite element fx
10993 return Roo.get(this.dom);
10997 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10998 animType = animType || 'run';
11000 var anim = Roo.lib.Anim[animType](
11002 (opt.duration || defaultDur) || .35,
11003 (opt.easing || defaultEase) || 'easeOut',
11005 Roo.callback(cb, this);
11014 // backwords compat
11015 Roo.Fx.resize = Roo.Fx.scale;
11017 //When included, Roo.Fx is automatically applied to Element so that all basic
11018 //effects are available directly via the Element API
11019 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11021 * Ext JS Library 1.1.1
11022 * Copyright(c) 2006-2007, Ext JS, LLC.
11024 * Originally Released Under LGPL - original licence link has changed is not relivant.
11027 * <script type="text/javascript">
11032 * @class Roo.CompositeElement
11033 * Standard composite class. Creates a Roo.Element for every element in the collection.
11035 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11036 * actions will be performed on all the elements in this collection.</b>
11038 * All methods return <i>this</i> and can be chained.
11040 var els = Roo.select("#some-el div.some-class", true);
11041 // or select directly from an existing element
11042 var el = Roo.get('some-el');
11043 el.select('div.some-class', true);
11045 els.setWidth(100); // all elements become 100 width
11046 els.hide(true); // all elements fade out and hide
11048 els.setWidth(100).hide(true);
11051 Roo.CompositeElement = function(els){
11052 this.elements = [];
11053 this.addElements(els);
11055 Roo.CompositeElement.prototype = {
11057 addElements : function(els){
11061 if(typeof els == "string"){
11062 els = Roo.Element.selectorFunction(els);
11064 var yels = this.elements;
11065 var index = yels.length-1;
11066 for(var i = 0, len = els.length; i < len; i++) {
11067 yels[++index] = Roo.get(els[i]);
11073 * Clears this composite and adds the elements returned by the passed selector.
11074 * @param {String/Array} els A string CSS selector, an array of elements or an element
11075 * @return {CompositeElement} this
11077 fill : function(els){
11078 this.elements = [];
11084 * Filters this composite to only elements that match the passed selector.
11085 * @param {String} selector A string CSS selector
11086 * @param {Boolean} inverse return inverse filter (not matches)
11087 * @return {CompositeElement} this
11089 filter : function(selector, inverse){
11091 inverse = inverse || false;
11092 this.each(function(el){
11093 var match = inverse ? !el.is(selector) : el.is(selector);
11095 els[els.length] = el.dom;
11102 invoke : function(fn, args){
11103 var els = this.elements;
11104 for(var i = 0, len = els.length; i < len; i++) {
11105 Roo.Element.prototype[fn].apply(els[i], args);
11110 * Adds elements to this composite.
11111 * @param {String/Array} els A string CSS selector, an array of elements or an element
11112 * @return {CompositeElement} this
11114 add : function(els){
11115 if(typeof els == "string"){
11116 this.addElements(Roo.Element.selectorFunction(els));
11117 }else if(els.length !== undefined){
11118 this.addElements(els);
11120 this.addElements([els]);
11125 * Calls the passed function passing (el, this, index) for each element in this composite.
11126 * @param {Function} fn The function to call
11127 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11128 * @return {CompositeElement} this
11130 each : function(fn, scope){
11131 var els = this.elements;
11132 for(var i = 0, len = els.length; i < len; i++){
11133 if(fn.call(scope || els[i], els[i], this, i) === false) {
11141 * Returns the Element object at the specified index
11142 * @param {Number} index
11143 * @return {Roo.Element}
11145 item : function(index){
11146 return this.elements[index] || null;
11150 * Returns the first Element
11151 * @return {Roo.Element}
11153 first : function(){
11154 return this.item(0);
11158 * Returns the last Element
11159 * @return {Roo.Element}
11162 return this.item(this.elements.length-1);
11166 * Returns the number of elements in this composite
11169 getCount : function(){
11170 return this.elements.length;
11174 * Returns true if this composite contains the passed element
11177 contains : function(el){
11178 return this.indexOf(el) !== -1;
11182 * Returns true if this composite contains the passed element
11185 indexOf : function(el){
11186 return this.elements.indexOf(Roo.get(el));
11191 * Removes the specified element(s).
11192 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11193 * or an array of any of those.
11194 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11195 * @return {CompositeElement} this
11197 removeElement : function(el, removeDom){
11198 if(el instanceof Array){
11199 for(var i = 0, len = el.length; i < len; i++){
11200 this.removeElement(el[i]);
11204 var index = typeof el == 'number' ? el : this.indexOf(el);
11207 var d = this.elements[index];
11211 d.parentNode.removeChild(d);
11214 this.elements.splice(index, 1);
11220 * Replaces the specified element with the passed element.
11221 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11223 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11224 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11225 * @return {CompositeElement} this
11227 replaceElement : function(el, replacement, domReplace){
11228 var index = typeof el == 'number' ? el : this.indexOf(el);
11231 this.elements[index].replaceWith(replacement);
11233 this.elements.splice(index, 1, Roo.get(replacement))
11240 * Removes all elements.
11242 clear : function(){
11243 this.elements = [];
11247 Roo.CompositeElement.createCall = function(proto, fnName){
11248 if(!proto[fnName]){
11249 proto[fnName] = function(){
11250 return this.invoke(fnName, arguments);
11254 for(var fnName in Roo.Element.prototype){
11255 if(typeof Roo.Element.prototype[fnName] == "function"){
11256 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11262 * Ext JS Library 1.1.1
11263 * Copyright(c) 2006-2007, Ext JS, LLC.
11265 * Originally Released Under LGPL - original licence link has changed is not relivant.
11268 * <script type="text/javascript">
11272 * @class Roo.CompositeElementLite
11273 * @extends Roo.CompositeElement
11274 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11276 var els = Roo.select("#some-el div.some-class");
11277 // or select directly from an existing element
11278 var el = Roo.get('some-el');
11279 el.select('div.some-class');
11281 els.setWidth(100); // all elements become 100 width
11282 els.hide(true); // all elements fade out and hide
11284 els.setWidth(100).hide(true);
11285 </code></pre><br><br>
11286 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11287 * actions will be performed on all the elements in this collection.</b>
11289 Roo.CompositeElementLite = function(els){
11290 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11291 this.el = new Roo.Element.Flyweight();
11293 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11294 addElements : function(els){
11296 if(els instanceof Array){
11297 this.elements = this.elements.concat(els);
11299 var yels = this.elements;
11300 var index = yels.length-1;
11301 for(var i = 0, len = els.length; i < len; i++) {
11302 yels[++index] = els[i];
11308 invoke : function(fn, args){
11309 var els = this.elements;
11311 for(var i = 0, len = els.length; i < len; i++) {
11313 Roo.Element.prototype[fn].apply(el, args);
11318 * Returns a flyweight Element of the dom element object at the specified index
11319 * @param {Number} index
11320 * @return {Roo.Element}
11322 item : function(index){
11323 if(!this.elements[index]){
11326 this.el.dom = this.elements[index];
11330 // fixes scope with flyweight
11331 addListener : function(eventName, handler, scope, opt){
11332 var els = this.elements;
11333 for(var i = 0, len = els.length; i < len; i++) {
11334 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11340 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11341 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11342 * a reference to the dom node, use el.dom.</b>
11343 * @param {Function} fn The function to call
11344 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11345 * @return {CompositeElement} this
11347 each : function(fn, scope){
11348 var els = this.elements;
11350 for(var i = 0, len = els.length; i < len; i++){
11352 if(fn.call(scope || el, el, this, i) === false){
11359 indexOf : function(el){
11360 return this.elements.indexOf(Roo.getDom(el));
11363 replaceElement : function(el, replacement, domReplace){
11364 var index = typeof el == 'number' ? el : this.indexOf(el);
11366 replacement = Roo.getDom(replacement);
11368 var d = this.elements[index];
11369 d.parentNode.insertBefore(replacement, d);
11370 d.parentNode.removeChild(d);
11372 this.elements.splice(index, 1, replacement);
11377 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11381 * Ext JS Library 1.1.1
11382 * Copyright(c) 2006-2007, Ext JS, LLC.
11384 * Originally Released Under LGPL - original licence link has changed is not relivant.
11387 * <script type="text/javascript">
11393 * @class Roo.data.Connection
11394 * @extends Roo.util.Observable
11395 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11396 * either to a configured URL, or to a URL specified at request time.<br><br>
11398 * Requests made by this class are asynchronous, and will return immediately. No data from
11399 * the server will be available to the statement immediately following the {@link #request} call.
11400 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11402 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11403 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11404 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11405 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11406 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11407 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11408 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11409 * standard DOM methods.
11411 * @param {Object} config a configuration object.
11413 Roo.data.Connection = function(config){
11414 Roo.apply(this, config);
11417 * @event beforerequest
11418 * Fires before a network request is made to retrieve a data object.
11419 * @param {Connection} conn This Connection object.
11420 * @param {Object} options The options config object passed to the {@link #request} method.
11422 "beforerequest" : true,
11424 * @event requestcomplete
11425 * Fires if the request was successfully completed.
11426 * @param {Connection} conn This Connection object.
11427 * @param {Object} response The XHR object containing the response data.
11428 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11429 * @param {Object} options The options config object passed to the {@link #request} method.
11431 "requestcomplete" : true,
11433 * @event requestexception
11434 * Fires if an error HTTP status was returned from the server.
11435 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11436 * @param {Connection} conn This Connection object.
11437 * @param {Object} response The XHR object containing the response data.
11438 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11439 * @param {Object} options The options config object passed to the {@link #request} method.
11441 "requestexception" : true
11443 Roo.data.Connection.superclass.constructor.call(this);
11446 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11448 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11451 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11452 * extra parameters to each request made by this object. (defaults to undefined)
11455 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11456 * to each request made by this object. (defaults to undefined)
11459 * @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)
11462 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11466 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11472 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11475 disableCaching: true,
11478 * Sends an HTTP request to a remote server.
11479 * @param {Object} options An object which may contain the following properties:<ul>
11480 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11481 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11482 * request, a url encoded string or a function to call to get either.</li>
11483 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11484 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11485 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11486 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11487 * <li>options {Object} The parameter to the request call.</li>
11488 * <li>success {Boolean} True if the request succeeded.</li>
11489 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11491 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11492 * The callback is passed the following parameters:<ul>
11493 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11494 * <li>options {Object} The parameter to the request call.</li>
11496 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11497 * The callback is passed the following parameters:<ul>
11498 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11499 * <li>options {Object} The parameter to the request call.</li>
11501 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11502 * for the callback function. Defaults to the browser window.</li>
11503 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11504 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11505 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11506 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11507 * params for the post data. Any params will be appended to the URL.</li>
11508 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11510 * @return {Number} transactionId
11512 request : function(o){
11513 if(this.fireEvent("beforerequest", this, o) !== false){
11516 if(typeof p == "function"){
11517 p = p.call(o.scope||window, o);
11519 if(typeof p == "object"){
11520 p = Roo.urlEncode(o.params);
11522 if(this.extraParams){
11523 var extras = Roo.urlEncode(this.extraParams);
11524 p = p ? (p + '&' + extras) : extras;
11527 var url = o.url || this.url;
11528 if(typeof url == 'function'){
11529 url = url.call(o.scope||window, o);
11533 var form = Roo.getDom(o.form);
11534 url = url || form.action;
11536 var enctype = form.getAttribute("enctype");
11537 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11538 return this.doFormUpload(o, p, url);
11540 var f = Roo.lib.Ajax.serializeForm(form);
11541 p = p ? (p + '&' + f) : f;
11544 var hs = o.headers;
11545 if(this.defaultHeaders){
11546 hs = Roo.apply(hs || {}, this.defaultHeaders);
11553 success: this.handleResponse,
11554 failure: this.handleFailure,
11556 argument: {options: o},
11557 timeout : o.timeout || this.timeout
11560 var method = o.method||this.method||(p ? "POST" : "GET");
11562 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11563 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11566 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11570 }else if(this.autoAbort !== false){
11574 if((method == 'GET' && p) || o.xmlData){
11575 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11578 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11579 return this.transId;
11581 Roo.callback(o.callback, o.scope, [o, null, null]);
11587 * Determine whether this object has a request outstanding.
11588 * @param {Number} transactionId (Optional) defaults to the last transaction
11589 * @return {Boolean} True if there is an outstanding request.
11591 isLoading : function(transId){
11593 return Roo.lib.Ajax.isCallInProgress(transId);
11595 return this.transId ? true : false;
11600 * Aborts any outstanding request.
11601 * @param {Number} transactionId (Optional) defaults to the last transaction
11603 abort : function(transId){
11604 if(transId || this.isLoading()){
11605 Roo.lib.Ajax.abort(transId || this.transId);
11610 handleResponse : function(response){
11611 this.transId = false;
11612 var options = response.argument.options;
11613 response.argument = options ? options.argument : null;
11614 this.fireEvent("requestcomplete", this, response, options);
11615 Roo.callback(options.success, options.scope, [response, options]);
11616 Roo.callback(options.callback, options.scope, [options, true, response]);
11620 handleFailure : function(response, e){
11621 this.transId = false;
11622 var options = response.argument.options;
11623 response.argument = options ? options.argument : null;
11624 this.fireEvent("requestexception", this, response, options, e);
11625 Roo.callback(options.failure, options.scope, [response, options]);
11626 Roo.callback(options.callback, options.scope, [options, false, response]);
11630 doFormUpload : function(o, ps, url){
11632 var frame = document.createElement('iframe');
11635 frame.className = 'x-hidden';
11637 frame.src = Roo.SSL_SECURE_URL;
11639 document.body.appendChild(frame);
11642 document.frames[id].name = id;
11645 var form = Roo.getDom(o.form);
11647 form.method = 'POST';
11648 form.enctype = form.encoding = 'multipart/form-data';
11654 if(ps){ // add dynamic params
11656 ps = Roo.urlDecode(ps, false);
11658 if(ps.hasOwnProperty(k)){
11659 hd = document.createElement('input');
11660 hd.type = 'hidden';
11663 form.appendChild(hd);
11670 var r = { // bogus response object
11675 r.argument = o ? o.argument : null;
11680 doc = frame.contentWindow.document;
11682 doc = (frame.contentDocument || window.frames[id].document);
11684 if(doc && doc.body){
11685 r.responseText = doc.body.innerHTML;
11687 if(doc && doc.XMLDocument){
11688 r.responseXML = doc.XMLDocument;
11690 r.responseXML = doc;
11697 Roo.EventManager.removeListener(frame, 'load', cb, this);
11699 this.fireEvent("requestcomplete", this, r, o);
11700 Roo.callback(o.success, o.scope, [r, o]);
11701 Roo.callback(o.callback, o.scope, [o, true, r]);
11703 setTimeout(function(){document.body.removeChild(frame);}, 100);
11706 Roo.EventManager.on(frame, 'load', cb, this);
11709 if(hiddens){ // remove dynamic params
11710 for(var i = 0, len = hiddens.length; i < len; i++){
11711 form.removeChild(hiddens[i]);
11718 * Ext JS Library 1.1.1
11719 * Copyright(c) 2006-2007, Ext JS, LLC.
11721 * Originally Released Under LGPL - original licence link has changed is not relivant.
11724 * <script type="text/javascript">
11728 * Global Ajax request class.
11731 * @extends Roo.data.Connection
11734 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11735 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11736 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11737 * @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)
11738 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11739 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11740 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11742 Roo.Ajax = new Roo.data.Connection({
11751 * Serialize the passed form into a url encoded string
11753 * @param {String/HTMLElement} form
11756 serializeForm : function(form){
11757 return Roo.lib.Ajax.serializeForm(form);
11761 * Ext JS Library 1.1.1
11762 * Copyright(c) 2006-2007, Ext JS, LLC.
11764 * Originally Released Under LGPL - original licence link has changed is not relivant.
11767 * <script type="text/javascript">
11772 * @class Roo.UpdateManager
11773 * @extends Roo.util.Observable
11774 * Provides AJAX-style update for Element object.<br><br>
11777 * // Get it from a Roo.Element object
11778 * var el = Roo.get("foo");
11779 * var mgr = el.getUpdateManager();
11780 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11782 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11784 * // or directly (returns the same UpdateManager instance)
11785 * var mgr = new Roo.UpdateManager("myElementId");
11786 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11787 * mgr.on("update", myFcnNeedsToKnow);
11789 // short handed call directly from the element object
11790 Roo.get("foo").load({
11794 text: "Loading Foo..."
11798 * Create new UpdateManager directly.
11799 * @param {String/HTMLElement/Roo.Element} el The element to update
11800 * @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).
11802 Roo.UpdateManager = function(el, forceNew){
11804 if(!forceNew && el.updateManager){
11805 return el.updateManager;
11808 * The Element object
11809 * @type Roo.Element
11813 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11816 this.defaultUrl = null;
11820 * @event beforeupdate
11821 * Fired before an update is made, return false from your handler and the update is cancelled.
11822 * @param {Roo.Element} el
11823 * @param {String/Object/Function} url
11824 * @param {String/Object} params
11826 "beforeupdate": true,
11829 * Fired after successful update is made.
11830 * @param {Roo.Element} el
11831 * @param {Object} oResponseObject The response Object
11836 * Fired on update failure.
11837 * @param {Roo.Element} el
11838 * @param {Object} oResponseObject The response Object
11842 var d = Roo.UpdateManager.defaults;
11844 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11847 this.sslBlankUrl = d.sslBlankUrl;
11849 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11852 this.disableCaching = d.disableCaching;
11854 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11857 this.indicatorText = d.indicatorText;
11859 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11862 this.showLoadIndicator = d.showLoadIndicator;
11864 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11867 this.timeout = d.timeout;
11870 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11873 this.loadScripts = d.loadScripts;
11876 * Transaction object of current executing transaction
11878 this.transaction = null;
11883 this.autoRefreshProcId = null;
11885 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11888 this.refreshDelegate = this.refresh.createDelegate(this);
11890 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11893 this.updateDelegate = this.update.createDelegate(this);
11895 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11898 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11902 this.successDelegate = this.processSuccess.createDelegate(this);
11906 this.failureDelegate = this.processFailure.createDelegate(this);
11908 if(!this.renderer){
11910 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11912 this.renderer = new Roo.UpdateManager.BasicRenderer();
11915 Roo.UpdateManager.superclass.constructor.call(this);
11918 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11920 * Get the Element this UpdateManager is bound to
11921 * @return {Roo.Element} The element
11923 getEl : function(){
11927 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11928 * @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:
11931 url: "your-url.php",<br/>
11932 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11933 callback: yourFunction,<br/>
11934 scope: yourObject, //(optional scope) <br/>
11935 discardUrl: false, <br/>
11936 nocache: false,<br/>
11937 text: "Loading...",<br/>
11939 scripts: false<br/>
11942 * The only required property is url. The optional properties nocache, text and scripts
11943 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11944 * @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}
11945 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11946 * @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.
11948 update : function(url, params, callback, discardUrl){
11949 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11950 var method = this.method,
11952 if(typeof url == "object"){ // must be config object
11955 params = params || cfg.params;
11956 callback = callback || cfg.callback;
11957 discardUrl = discardUrl || cfg.discardUrl;
11958 if(callback && cfg.scope){
11959 callback = callback.createDelegate(cfg.scope);
11961 if(typeof cfg.method != "undefined"){method = cfg.method;};
11962 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11963 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11964 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11965 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11967 this.showLoading();
11969 this.defaultUrl = url;
11971 if(typeof url == "function"){
11972 url = url.call(this);
11975 method = method || (params ? "POST" : "GET");
11976 if(method == "GET"){
11977 url = this.prepareUrl(url);
11980 var o = Roo.apply(cfg ||{}, {
11983 success: this.successDelegate,
11984 failure: this.failureDelegate,
11985 callback: undefined,
11986 timeout: (this.timeout*1000),
11987 argument: {"url": url, "form": null, "callback": callback, "params": params}
11989 Roo.log("updated manager called with timeout of " + o.timeout);
11990 this.transaction = Roo.Ajax.request(o);
11995 * 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.
11996 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11997 * @param {String/HTMLElement} form The form Id or form element
11998 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11999 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12000 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12002 formUpdate : function(form, url, reset, callback){
12003 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12004 if(typeof url == "function"){
12005 url = url.call(this);
12007 form = Roo.getDom(form);
12008 this.transaction = Roo.Ajax.request({
12011 success: this.successDelegate,
12012 failure: this.failureDelegate,
12013 timeout: (this.timeout*1000),
12014 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12016 this.showLoading.defer(1, this);
12021 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12022 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12024 refresh : function(callback){
12025 if(this.defaultUrl == null){
12028 this.update(this.defaultUrl, null, callback, true);
12032 * Set this element to auto refresh.
12033 * @param {Number} interval How often to update (in seconds).
12034 * @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)
12035 * @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}
12036 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12037 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12039 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12041 this.update(url || this.defaultUrl, params, callback, true);
12043 if(this.autoRefreshProcId){
12044 clearInterval(this.autoRefreshProcId);
12046 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12050 * Stop auto refresh on this element.
12052 stopAutoRefresh : function(){
12053 if(this.autoRefreshProcId){
12054 clearInterval(this.autoRefreshProcId);
12055 delete this.autoRefreshProcId;
12059 isAutoRefreshing : function(){
12060 return this.autoRefreshProcId ? true : false;
12063 * Called to update the element to "Loading" state. Override to perform custom action.
12065 showLoading : function(){
12066 if(this.showLoadIndicator){
12067 this.el.update(this.indicatorText);
12072 * Adds unique parameter to query string if disableCaching = true
12075 prepareUrl : function(url){
12076 if(this.disableCaching){
12077 var append = "_dc=" + (new Date().getTime());
12078 if(url.indexOf("?") !== -1){
12079 url += "&" + append;
12081 url += "?" + append;
12090 processSuccess : function(response){
12091 this.transaction = null;
12092 if(response.argument.form && response.argument.reset){
12093 try{ // put in try/catch since some older FF releases had problems with this
12094 response.argument.form.reset();
12097 if(this.loadScripts){
12098 this.renderer.render(this.el, response, this,
12099 this.updateComplete.createDelegate(this, [response]));
12101 this.renderer.render(this.el, response, this);
12102 this.updateComplete(response);
12106 updateComplete : function(response){
12107 this.fireEvent("update", this.el, response);
12108 if(typeof response.argument.callback == "function"){
12109 response.argument.callback(this.el, true, response);
12116 processFailure : function(response){
12117 this.transaction = null;
12118 this.fireEvent("failure", this.el, response);
12119 if(typeof response.argument.callback == "function"){
12120 response.argument.callback(this.el, false, response);
12125 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12126 * @param {Object} renderer The object implementing the render() method
12128 setRenderer : function(renderer){
12129 this.renderer = renderer;
12132 getRenderer : function(){
12133 return this.renderer;
12137 * Set the defaultUrl used for updates
12138 * @param {String/Function} defaultUrl The url or a function to call to get the url
12140 setDefaultUrl : function(defaultUrl){
12141 this.defaultUrl = defaultUrl;
12145 * Aborts the executing transaction
12147 abort : function(){
12148 if(this.transaction){
12149 Roo.Ajax.abort(this.transaction);
12154 * Returns true if an update is in progress
12155 * @return {Boolean}
12157 isUpdating : function(){
12158 if(this.transaction){
12159 return Roo.Ajax.isLoading(this.transaction);
12166 * @class Roo.UpdateManager.defaults
12167 * @static (not really - but it helps the doc tool)
12168 * The defaults collection enables customizing the default properties of UpdateManager
12170 Roo.UpdateManager.defaults = {
12172 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12178 * True to process scripts by default (Defaults to false).
12181 loadScripts : false,
12184 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12187 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12189 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12192 disableCaching : false,
12194 * Whether to show indicatorText when loading (Defaults to true).
12197 showLoadIndicator : true,
12199 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12202 indicatorText : '<div class="loading-indicator">Loading...</div>'
12206 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12208 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12209 * @param {String/HTMLElement/Roo.Element} el The element to update
12210 * @param {String} url The url
12211 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12212 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12215 * @member Roo.UpdateManager
12217 Roo.UpdateManager.updateElement = function(el, url, params, options){
12218 var um = Roo.get(el, true).getUpdateManager();
12219 Roo.apply(um, options);
12220 um.update(url, params, options ? options.callback : null);
12222 // alias for backwards compat
12223 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12225 * @class Roo.UpdateManager.BasicRenderer
12226 * Default Content renderer. Updates the elements innerHTML with the responseText.
12228 Roo.UpdateManager.BasicRenderer = function(){};
12230 Roo.UpdateManager.BasicRenderer.prototype = {
12232 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12233 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12234 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12235 * @param {Roo.Element} el The element being rendered
12236 * @param {Object} response The YUI Connect response object
12237 * @param {UpdateManager} updateManager The calling update manager
12238 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12240 render : function(el, response, updateManager, callback){
12241 el.update(response.responseText, updateManager.loadScripts, callback);
12247 * (c)) Alan Knowles
12253 * @class Roo.DomTemplate
12254 * @extends Roo.Template
12255 * An effort at a dom based template engine..
12257 * Similar to XTemplate, except it uses dom parsing to create the template..
12259 * Supported features:
12264 {a_variable} - output encoded.
12265 {a_variable.format:("Y-m-d")} - call a method on the variable
12266 {a_variable:raw} - unencoded output
12267 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12268 {a_variable:this.method_on_template(...)} - call a method on the template object.
12273 <div roo-for="a_variable or condition.."></div>
12274 <div roo-if="a_variable or condition"></div>
12275 <div roo-exec="some javascript"></div>
12276 <div roo-name="named_template"></div>
12281 Roo.DomTemplate = function()
12283 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12290 Roo.extend(Roo.DomTemplate, Roo.Template, {
12292 * id counter for sub templates.
12296 * flag to indicate if dom parser is inside a pre,
12297 * it will strip whitespace if not.
12302 * The various sub templates
12310 * basic tag replacing syntax
12313 * // you can fake an object call by doing this
12317 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12318 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12320 iterChild : function (node, method) {
12322 var oldPre = this.inPre;
12323 if (node.tagName == 'PRE') {
12326 for( var i = 0; i < node.childNodes.length; i++) {
12327 method.call(this, node.childNodes[i]);
12329 this.inPre = oldPre;
12335 * compile the template
12337 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12340 compile: function()
12344 // covert the html into DOM...
12348 doc = document.implementation.createHTMLDocument("");
12349 doc.documentElement.innerHTML = this.html ;
12350 div = doc.documentElement;
12352 // old IE... - nasty -- it causes all sorts of issues.. with
12353 // images getting pulled from server..
12354 div = document.createElement('div');
12355 div.innerHTML = this.html;
12357 //doc.documentElement.innerHTML = htmlBody
12363 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12365 var tpls = this.tpls;
12367 // create a top level template from the snippet..
12369 //Roo.log(div.innerHTML);
12376 body : div.innerHTML,
12389 Roo.each(tpls, function(tp){
12390 this.compileTpl(tp);
12391 this.tpls[tp.id] = tp;
12394 this.master = tpls[0];
12400 compileNode : function(node, istop) {
12405 // skip anything not a tag..
12406 if (node.nodeType != 1) {
12407 if (node.nodeType == 3 && !this.inPre) {
12408 // reduce white space..
12409 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12432 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12433 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12434 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12435 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12441 // just itterate children..
12442 this.iterChild(node,this.compileNode);
12445 tpl.uid = this.id++;
12446 tpl.value = node.getAttribute('roo-' + tpl.attr);
12447 node.removeAttribute('roo-'+ tpl.attr);
12448 if (tpl.attr != 'name') {
12449 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12450 node.parentNode.replaceChild(placeholder, node);
12453 var placeholder = document.createElement('span');
12454 placeholder.className = 'roo-tpl-' + tpl.value;
12455 node.parentNode.replaceChild(placeholder, node);
12458 // parent now sees '{domtplXXXX}
12459 this.iterChild(node,this.compileNode);
12461 // we should now have node body...
12462 var div = document.createElement('div');
12463 div.appendChild(node);
12465 // this has the unfortunate side effect of converting tagged attributes
12466 // eg. href="{...}" into %7C...%7D
12467 // this has been fixed by searching for those combo's although it's a bit hacky..
12470 tpl.body = div.innerHTML;
12477 switch (tpl.value) {
12478 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12479 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12480 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12485 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12489 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12493 tpl.id = tpl.value; // replace non characters???
12499 this.tpls.push(tpl);
12509 * Compile a segment of the template into a 'sub-template'
12515 compileTpl : function(tpl)
12517 var fm = Roo.util.Format;
12518 var useF = this.disableFormats !== true;
12520 var sep = Roo.isGecko ? "+\n" : ",\n";
12522 var undef = function(str) {
12523 Roo.debug && Roo.log("Property not found :" + str);
12527 //Roo.log(tpl.body);
12531 var fn = function(m, lbrace, name, format, args)
12534 //Roo.log(arguments);
12535 args = args ? args.replace(/\\'/g,"'") : args;
12536 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12537 if (typeof(format) == 'undefined') {
12538 format = 'htmlEncode';
12540 if (format == 'raw' ) {
12544 if(name.substr(0, 6) == 'domtpl'){
12545 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12548 // build an array of options to determine if value is undefined..
12550 // basically get 'xxxx.yyyy' then do
12551 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12552 // (function () { Roo.log("Property not found"); return ''; })() :
12557 Roo.each(name.split('.'), function(st) {
12558 lookfor += (lookfor.length ? '.': '') + st;
12559 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12562 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12565 if(format && useF){
12567 args = args ? ',' + args : "";
12569 if(format.substr(0, 5) != "this."){
12570 format = "fm." + format + '(';
12572 format = 'this.call("'+ format.substr(5) + '", ';
12576 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12579 if (args && args.length) {
12580 // called with xxyx.yuu:(test,test)
12582 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12584 // raw.. - :raw modifier..
12585 return "'"+ sep + udef_st + name + ")"+sep+"'";
12589 // branched to use + in gecko and [].join() in others
12591 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12592 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12595 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12596 body.push(tpl.body.replace(/(\r\n|\n)/g,
12597 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12598 body.push("'].join('');};};");
12599 body = body.join('');
12602 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12604 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12611 * same as applyTemplate, except it's done to one of the subTemplates
12612 * when using named templates, you can do:
12614 * var str = pl.applySubTemplate('your-name', values);
12617 * @param {Number} id of the template
12618 * @param {Object} values to apply to template
12619 * @param {Object} parent (normaly the instance of this object)
12621 applySubTemplate : function(id, values, parent)
12625 var t = this.tpls[id];
12629 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12630 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12634 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12641 if(t.execCall && t.execCall.call(this, values, parent)){
12645 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12651 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12652 parent = t.target ? values : parent;
12653 if(t.forCall && vs instanceof Array){
12655 for(var i = 0, len = vs.length; i < len; i++){
12657 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12659 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12661 //Roo.log(t.compiled);
12665 return buf.join('');
12668 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12673 return t.compiled.call(this, vs, parent);
12675 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12677 //Roo.log(t.compiled);
12685 applyTemplate : function(values){
12686 return this.master.compiled.call(this, values, {});
12687 //var s = this.subs;
12690 apply : function(){
12691 return this.applyTemplate.apply(this, arguments);
12696 Roo.DomTemplate.from = function(el){
12697 el = Roo.getDom(el);
12698 return new Roo.Domtemplate(el.value || el.innerHTML);
12701 * Ext JS Library 1.1.1
12702 * Copyright(c) 2006-2007, Ext JS, LLC.
12704 * Originally Released Under LGPL - original licence link has changed is not relivant.
12707 * <script type="text/javascript">
12711 * @class Roo.util.DelayedTask
12712 * Provides a convenient method of performing setTimeout where a new
12713 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12714 * You can use this class to buffer
12715 * the keypress events for a certain number of milliseconds, and perform only if they stop
12716 * for that amount of time.
12717 * @constructor The parameters to this constructor serve as defaults and are not required.
12718 * @param {Function} fn (optional) The default function to timeout
12719 * @param {Object} scope (optional) The default scope of that timeout
12720 * @param {Array} args (optional) The default Array of arguments
12722 Roo.util.DelayedTask = function(fn, scope, args){
12723 var id = null, d, t;
12725 var call = function(){
12726 var now = new Date().getTime();
12730 fn.apply(scope, args || []);
12734 * Cancels any pending timeout and queues a new one
12735 * @param {Number} delay The milliseconds to delay
12736 * @param {Function} newFn (optional) Overrides function passed to constructor
12737 * @param {Object} newScope (optional) Overrides scope passed to constructor
12738 * @param {Array} newArgs (optional) Overrides args passed to constructor
12740 this.delay = function(delay, newFn, newScope, newArgs){
12741 if(id && delay != d){
12745 t = new Date().getTime();
12747 scope = newScope || scope;
12748 args = newArgs || args;
12750 id = setInterval(call, d);
12755 * Cancel the last queued timeout
12757 this.cancel = function(){
12765 * Ext JS Library 1.1.1
12766 * Copyright(c) 2006-2007, Ext JS, LLC.
12768 * Originally Released Under LGPL - original licence link has changed is not relivant.
12771 * <script type="text/javascript">
12775 Roo.util.TaskRunner = function(interval){
12776 interval = interval || 10;
12777 var tasks = [], removeQueue = [];
12779 var running = false;
12781 var stopThread = function(){
12787 var startThread = function(){
12790 id = setInterval(runTasks, interval);
12794 var removeTask = function(task){
12795 removeQueue.push(task);
12801 var runTasks = function(){
12802 if(removeQueue.length > 0){
12803 for(var i = 0, len = removeQueue.length; i < len; i++){
12804 tasks.remove(removeQueue[i]);
12807 if(tasks.length < 1){
12812 var now = new Date().getTime();
12813 for(var i = 0, len = tasks.length; i < len; ++i){
12815 var itime = now - t.taskRunTime;
12816 if(t.interval <= itime){
12817 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12818 t.taskRunTime = now;
12819 if(rt === false || t.taskRunCount === t.repeat){
12824 if(t.duration && t.duration <= (now - t.taskStartTime)){
12831 * Queues a new task.
12832 * @param {Object} task
12834 this.start = function(task){
12836 task.taskStartTime = new Date().getTime();
12837 task.taskRunTime = 0;
12838 task.taskRunCount = 0;
12843 this.stop = function(task){
12848 this.stopAll = function(){
12850 for(var i = 0, len = tasks.length; i < len; i++){
12851 if(tasks[i].onStop){
12860 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12862 * Ext JS Library 1.1.1
12863 * Copyright(c) 2006-2007, Ext JS, LLC.
12865 * Originally Released Under LGPL - original licence link has changed is not relivant.
12868 * <script type="text/javascript">
12873 * @class Roo.util.MixedCollection
12874 * @extends Roo.util.Observable
12875 * A Collection class that maintains both numeric indexes and keys and exposes events.
12877 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12878 * collection (defaults to false)
12879 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12880 * and return the key value for that item. This is used when available to look up the key on items that
12881 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12882 * equivalent to providing an implementation for the {@link #getKey} method.
12884 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12892 * Fires when the collection is cleared.
12897 * Fires when an item is added to the collection.
12898 * @param {Number} index The index at which the item was added.
12899 * @param {Object} o The item added.
12900 * @param {String} key The key associated with the added item.
12905 * Fires when an item is replaced in the collection.
12906 * @param {String} key he key associated with the new added.
12907 * @param {Object} old The item being replaced.
12908 * @param {Object} new The new item.
12913 * Fires when an item is removed from the collection.
12914 * @param {Object} o The item being removed.
12915 * @param {String} key (optional) The key associated with the removed item.
12920 this.allowFunctions = allowFunctions === true;
12922 this.getKey = keyFn;
12924 Roo.util.MixedCollection.superclass.constructor.call(this);
12927 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12928 allowFunctions : false,
12931 * Adds an item to the collection.
12932 * @param {String} key The key to associate with the item
12933 * @param {Object} o The item to add.
12934 * @return {Object} The item added.
12936 add : function(key, o){
12937 if(arguments.length == 1){
12939 key = this.getKey(o);
12941 if(typeof key == "undefined" || key === null){
12943 this.items.push(o);
12944 this.keys.push(null);
12946 var old = this.map[key];
12948 return this.replace(key, o);
12951 this.items.push(o);
12953 this.keys.push(key);
12955 this.fireEvent("add", this.length-1, o, key);
12960 * MixedCollection has a generic way to fetch keys if you implement getKey.
12963 var mc = new Roo.util.MixedCollection();
12964 mc.add(someEl.dom.id, someEl);
12965 mc.add(otherEl.dom.id, otherEl);
12969 var mc = new Roo.util.MixedCollection();
12970 mc.getKey = function(el){
12976 // or via the constructor
12977 var mc = new Roo.util.MixedCollection(false, function(el){
12983 * @param o {Object} The item for which to find the key.
12984 * @return {Object} The key for the passed item.
12986 getKey : function(o){
12991 * Replaces an item in the collection.
12992 * @param {String} key The key associated with the item to replace, or the item to replace.
12993 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12994 * @return {Object} The new item.
12996 replace : function(key, o){
12997 if(arguments.length == 1){
12999 key = this.getKey(o);
13001 var old = this.item(key);
13002 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13003 return this.add(key, o);
13005 var index = this.indexOfKey(key);
13006 this.items[index] = o;
13008 this.fireEvent("replace", key, old, o);
13013 * Adds all elements of an Array or an Object to the collection.
13014 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13015 * an Array of values, each of which are added to the collection.
13017 addAll : function(objs){
13018 if(arguments.length > 1 || objs instanceof Array){
13019 var args = arguments.length > 1 ? arguments : objs;
13020 for(var i = 0, len = args.length; i < len; i++){
13024 for(var key in objs){
13025 if(this.allowFunctions || typeof objs[key] != "function"){
13026 this.add(key, objs[key]);
13033 * Executes the specified function once for every item in the collection, passing each
13034 * item as the first and only parameter. returning false from the function will stop the iteration.
13035 * @param {Function} fn The function to execute for each item.
13036 * @param {Object} scope (optional) The scope in which to execute the function.
13038 each : function(fn, scope){
13039 var items = [].concat(this.items); // each safe for removal
13040 for(var i = 0, len = items.length; i < len; i++){
13041 if(fn.call(scope || items[i], items[i], i, len) === false){
13048 * Executes the specified function once for every key in the collection, passing each
13049 * key, and its associated item as the first two parameters.
13050 * @param {Function} fn The function to execute for each item.
13051 * @param {Object} scope (optional) The scope in which to execute the function.
13053 eachKey : function(fn, scope){
13054 for(var i = 0, len = this.keys.length; i < len; i++){
13055 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13060 * Returns the first item in the collection which elicits a true return value from the
13061 * passed selection function.
13062 * @param {Function} fn The selection function to execute for each item.
13063 * @param {Object} scope (optional) The scope in which to execute the function.
13064 * @return {Object} The first item in the collection which returned true from the selection function.
13066 find : function(fn, scope){
13067 for(var i = 0, len = this.items.length; i < len; i++){
13068 if(fn.call(scope || window, this.items[i], this.keys[i])){
13069 return this.items[i];
13076 * Inserts an item at the specified index in the collection.
13077 * @param {Number} index The index to insert the item at.
13078 * @param {String} key The key to associate with the new item, or the item itself.
13079 * @param {Object} o (optional) If the second parameter was a key, the new item.
13080 * @return {Object} The item inserted.
13082 insert : function(index, key, o){
13083 if(arguments.length == 2){
13085 key = this.getKey(o);
13087 if(index >= this.length){
13088 return this.add(key, o);
13091 this.items.splice(index, 0, o);
13092 if(typeof key != "undefined" && key != null){
13095 this.keys.splice(index, 0, key);
13096 this.fireEvent("add", index, o, key);
13101 * Removed an item from the collection.
13102 * @param {Object} o The item to remove.
13103 * @return {Object} The item removed.
13105 remove : function(o){
13106 return this.removeAt(this.indexOf(o));
13110 * Remove an item from a specified index in the collection.
13111 * @param {Number} index The index within the collection of the item to remove.
13113 removeAt : function(index){
13114 if(index < this.length && index >= 0){
13116 var o = this.items[index];
13117 this.items.splice(index, 1);
13118 var key = this.keys[index];
13119 if(typeof key != "undefined"){
13120 delete this.map[key];
13122 this.keys.splice(index, 1);
13123 this.fireEvent("remove", o, key);
13128 * Removed an item associated with the passed key fom the collection.
13129 * @param {String} key The key of the item to remove.
13131 removeKey : function(key){
13132 return this.removeAt(this.indexOfKey(key));
13136 * Returns the number of items in the collection.
13137 * @return {Number} the number of items in the collection.
13139 getCount : function(){
13140 return this.length;
13144 * Returns index within the collection of the passed Object.
13145 * @param {Object} o The item to find the index of.
13146 * @return {Number} index of the item.
13148 indexOf : function(o){
13149 if(!this.items.indexOf){
13150 for(var i = 0, len = this.items.length; i < len; i++){
13151 if(this.items[i] == o) {
13157 return this.items.indexOf(o);
13162 * Returns index within the collection of the passed key.
13163 * @param {String} key The key to find the index of.
13164 * @return {Number} index of the key.
13166 indexOfKey : function(key){
13167 if(!this.keys.indexOf){
13168 for(var i = 0, len = this.keys.length; i < len; i++){
13169 if(this.keys[i] == key) {
13175 return this.keys.indexOf(key);
13180 * Returns the item associated with the passed key OR index. Key has priority over index.
13181 * @param {String/Number} key The key or index of the item.
13182 * @return {Object} The item associated with the passed key.
13184 item : function(key){
13185 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13186 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13190 * Returns the item at the specified index.
13191 * @param {Number} index The index of the item.
13194 itemAt : function(index){
13195 return this.items[index];
13199 * Returns the item associated with the passed key.
13200 * @param {String/Number} key The key of the item.
13201 * @return {Object} The item associated with the passed key.
13203 key : function(key){
13204 return this.map[key];
13208 * Returns true if the collection contains the passed Object as an item.
13209 * @param {Object} o The Object to look for in the collection.
13210 * @return {Boolean} True if the collection contains the Object as an item.
13212 contains : function(o){
13213 return this.indexOf(o) != -1;
13217 * Returns true if the collection contains the passed Object as a key.
13218 * @param {String} key The key to look for in the collection.
13219 * @return {Boolean} True if the collection contains the Object as a key.
13221 containsKey : function(key){
13222 return typeof this.map[key] != "undefined";
13226 * Removes all items from the collection.
13228 clear : function(){
13233 this.fireEvent("clear");
13237 * Returns the first item in the collection.
13238 * @return {Object} the first item in the collection..
13240 first : function(){
13241 return this.items[0];
13245 * Returns the last item in the collection.
13246 * @return {Object} the last item in the collection..
13249 return this.items[this.length-1];
13252 _sort : function(property, dir, fn){
13253 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13254 fn = fn || function(a, b){
13257 var c = [], k = this.keys, items = this.items;
13258 for(var i = 0, len = items.length; i < len; i++){
13259 c[c.length] = {key: k[i], value: items[i], index: i};
13261 c.sort(function(a, b){
13262 var v = fn(a[property], b[property]) * dsc;
13264 v = (a.index < b.index ? -1 : 1);
13268 for(var i = 0, len = c.length; i < len; i++){
13269 items[i] = c[i].value;
13272 this.fireEvent("sort", this);
13276 * Sorts this collection with the passed comparison function
13277 * @param {String} direction (optional) "ASC" or "DESC"
13278 * @param {Function} fn (optional) comparison function
13280 sort : function(dir, fn){
13281 this._sort("value", dir, fn);
13285 * Sorts this collection by keys
13286 * @param {String} direction (optional) "ASC" or "DESC"
13287 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13289 keySort : function(dir, fn){
13290 this._sort("key", dir, fn || function(a, b){
13291 return String(a).toUpperCase()-String(b).toUpperCase();
13296 * Returns a range of items in this collection
13297 * @param {Number} startIndex (optional) defaults to 0
13298 * @param {Number} endIndex (optional) default to the last item
13299 * @return {Array} An array of items
13301 getRange : function(start, end){
13302 var items = this.items;
13303 if(items.length < 1){
13306 start = start || 0;
13307 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13310 for(var i = start; i <= end; i++) {
13311 r[r.length] = items[i];
13314 for(var i = start; i >= end; i--) {
13315 r[r.length] = items[i];
13322 * Filter the <i>objects</i> in this collection by a specific property.
13323 * Returns a new collection that has been filtered.
13324 * @param {String} property A property on your objects
13325 * @param {String/RegExp} value Either string that the property values
13326 * should start with or a RegExp to test against the property
13327 * @return {MixedCollection} The new filtered collection
13329 filter : function(property, value){
13330 if(!value.exec){ // not a regex
13331 value = String(value);
13332 if(value.length == 0){
13333 return this.clone();
13335 value = new RegExp("^" + Roo.escapeRe(value), "i");
13337 return this.filterBy(function(o){
13338 return o && value.test(o[property]);
13343 * Filter by a function. * Returns a new collection that has been filtered.
13344 * The passed function will be called with each
13345 * object in the collection. If the function returns true, the value is included
13346 * otherwise it is filtered.
13347 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13348 * @param {Object} scope (optional) The scope of the function (defaults to this)
13349 * @return {MixedCollection} The new filtered collection
13351 filterBy : function(fn, scope){
13352 var r = new Roo.util.MixedCollection();
13353 r.getKey = this.getKey;
13354 var k = this.keys, it = this.items;
13355 for(var i = 0, len = it.length; i < len; i++){
13356 if(fn.call(scope||this, it[i], k[i])){
13357 r.add(k[i], it[i]);
13364 * Creates a duplicate of this collection
13365 * @return {MixedCollection}
13367 clone : function(){
13368 var r = new Roo.util.MixedCollection();
13369 var k = this.keys, it = this.items;
13370 for(var i = 0, len = it.length; i < len; i++){
13371 r.add(k[i], it[i]);
13373 r.getKey = this.getKey;
13378 * Returns the item associated with the passed key or index.
13380 * @param {String/Number} key The key or index of the item.
13381 * @return {Object} The item associated with the passed key.
13383 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13385 * Ext JS Library 1.1.1
13386 * Copyright(c) 2006-2007, Ext JS, LLC.
13388 * Originally Released Under LGPL - original licence link has changed is not relivant.
13391 * <script type="text/javascript">
13394 * @class Roo.util.JSON
13395 * Modified version of Douglas Crockford"s json.js that doesn"t
13396 * mess with the Object prototype
13397 * http://www.json.org/js.html
13400 Roo.util.JSON = new (function(){
13401 var useHasOwn = {}.hasOwnProperty ? true : false;
13403 // crashes Safari in some instances
13404 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13406 var pad = function(n) {
13407 return n < 10 ? "0" + n : n;
13420 var encodeString = function(s){
13421 if (/["\\\x00-\x1f]/.test(s)) {
13422 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13427 c = b.charCodeAt();
13429 Math.floor(c / 16).toString(16) +
13430 (c % 16).toString(16);
13433 return '"' + s + '"';
13436 var encodeArray = function(o){
13437 var a = ["["], b, i, l = o.length, v;
13438 for (i = 0; i < l; i += 1) {
13440 switch (typeof v) {
13449 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13457 var encodeDate = function(o){
13458 return '"' + o.getFullYear() + "-" +
13459 pad(o.getMonth() + 1) + "-" +
13460 pad(o.getDate()) + "T" +
13461 pad(o.getHours()) + ":" +
13462 pad(o.getMinutes()) + ":" +
13463 pad(o.getSeconds()) + '"';
13467 * Encodes an Object, Array or other value
13468 * @param {Mixed} o The variable to encode
13469 * @return {String} The JSON string
13471 this.encode = function(o)
13473 // should this be extended to fully wrap stringify..
13475 if(typeof o == "undefined" || o === null){
13477 }else if(o instanceof Array){
13478 return encodeArray(o);
13479 }else if(o instanceof Date){
13480 return encodeDate(o);
13481 }else if(typeof o == "string"){
13482 return encodeString(o);
13483 }else if(typeof o == "number"){
13484 return isFinite(o) ? String(o) : "null";
13485 }else if(typeof o == "boolean"){
13488 var a = ["{"], b, i, v;
13490 if(!useHasOwn || o.hasOwnProperty(i)) {
13492 switch (typeof v) {
13501 a.push(this.encode(i), ":",
13502 v === null ? "null" : this.encode(v));
13513 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13514 * @param {String} json The JSON string
13515 * @return {Object} The resulting object
13517 this.decode = function(json){
13519 return /** eval:var:json */ eval("(" + json + ')');
13523 * Shorthand for {@link Roo.util.JSON#encode}
13524 * @member Roo encode
13526 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13528 * Shorthand for {@link Roo.util.JSON#decode}
13529 * @member Roo decode
13531 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13534 * Ext JS Library 1.1.1
13535 * Copyright(c) 2006-2007, Ext JS, LLC.
13537 * Originally Released Under LGPL - original licence link has changed is not relivant.
13540 * <script type="text/javascript">
13544 * @class Roo.util.Format
13545 * Reusable data formatting functions
13548 Roo.util.Format = function(){
13549 var trimRe = /^\s+|\s+$/g;
13552 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13553 * @param {String} value The string to truncate
13554 * @param {Number} length The maximum length to allow before truncating
13555 * @return {String} The converted text
13557 ellipsis : function(value, len){
13558 if(value && value.length > len){
13559 return value.substr(0, len-3)+"...";
13565 * Checks a reference and converts it to empty string if it is undefined
13566 * @param {Mixed} value Reference to check
13567 * @return {Mixed} Empty string if converted, otherwise the original value
13569 undef : function(value){
13570 return typeof value != "undefined" ? value : "";
13574 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13575 * @param {String} value The string to encode
13576 * @return {String} The encoded text
13578 htmlEncode : function(value){
13579 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13583 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13584 * @param {String} value The string to decode
13585 * @return {String} The decoded text
13587 htmlDecode : function(value){
13588 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13592 * Trims any whitespace from either side of a string
13593 * @param {String} value The text to trim
13594 * @return {String} The trimmed text
13596 trim : function(value){
13597 return String(value).replace(trimRe, "");
13601 * Returns a substring from within an original string
13602 * @param {String} value The original text
13603 * @param {Number} start The start index of the substring
13604 * @param {Number} length The length of the substring
13605 * @return {String} The substring
13607 substr : function(value, start, length){
13608 return String(value).substr(start, length);
13612 * Converts a string to all lower case letters
13613 * @param {String} value The text to convert
13614 * @return {String} The converted text
13616 lowercase : function(value){
13617 return String(value).toLowerCase();
13621 * Converts a string to all upper case letters
13622 * @param {String} value The text to convert
13623 * @return {String} The converted text
13625 uppercase : function(value){
13626 return String(value).toUpperCase();
13630 * Converts the first character only of a string to upper case
13631 * @param {String} value The text to convert
13632 * @return {String} The converted text
13634 capitalize : function(value){
13635 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13639 call : function(value, fn){
13640 if(arguments.length > 2){
13641 var args = Array.prototype.slice.call(arguments, 2);
13642 args.unshift(value);
13644 return /** eval:var:value */ eval(fn).apply(window, args);
13646 /** eval:var:value */
13647 return /** eval:var:value */ eval(fn).call(window, value);
13653 * safer version of Math.toFixed..??/
13654 * @param {Number/String} value The numeric value to format
13655 * @param {Number/String} value Decimal places
13656 * @return {String} The formatted currency string
13658 toFixed : function(v, n)
13660 // why not use to fixed - precision is buggered???
13662 return Math.round(v-0);
13664 var fact = Math.pow(10,n+1);
13665 v = (Math.round((v-0)*fact))/fact;
13666 var z = (''+fact).substring(2);
13667 if (v == Math.floor(v)) {
13668 return Math.floor(v) + '.' + z;
13671 // now just padd decimals..
13672 var ps = String(v).split('.');
13673 var fd = (ps[1] + z);
13674 var r = fd.substring(0,n);
13675 var rm = fd.substring(n);
13677 return ps[0] + '.' + r;
13679 r*=1; // turn it into a number;
13681 if (String(r).length != n) {
13684 r = String(r).substring(1); // chop the end off.
13687 return ps[0] + '.' + r;
13692 * Format a number as US currency
13693 * @param {Number/String} value The numeric value to format
13694 * @return {String} The formatted currency string
13696 usMoney : function(v){
13697 return '$' + Roo.util.Format.number(v);
13702 * eventually this should probably emulate php's number_format
13703 * @param {Number/String} value The numeric value to format
13704 * @param {Number} decimals number of decimal places
13705 * @return {String} The formatted currency string
13707 number : function(v,decimals)
13709 // multiply and round.
13710 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13711 var mul = Math.pow(10, decimals);
13712 var zero = String(mul).substring(1);
13713 v = (Math.round((v-0)*mul))/mul;
13715 // if it's '0' number.. then
13717 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13719 var ps = v.split('.');
13723 var r = /(\d+)(\d{3})/;
13725 while (r.test(whole)) {
13726 whole = whole.replace(r, '$1' + ',' + '$2');
13732 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13733 // does not have decimals
13734 (decimals ? ('.' + zero) : '');
13737 return whole + sub ;
13741 * Parse a value into a formatted date using the specified format pattern.
13742 * @param {Mixed} value The value to format
13743 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13744 * @return {String} The formatted date string
13746 date : function(v, format){
13750 if(!(v instanceof Date)){
13751 v = new Date(Date.parse(v));
13753 return v.dateFormat(format || Roo.util.Format.defaults.date);
13757 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13758 * @param {String} format Any valid date format string
13759 * @return {Function} The date formatting function
13761 dateRenderer : function(format){
13762 return function(v){
13763 return Roo.util.Format.date(v, format);
13768 stripTagsRE : /<\/?[^>]+>/gi,
13771 * Strips all HTML tags
13772 * @param {Mixed} value The text from which to strip tags
13773 * @return {String} The stripped text
13775 stripTags : function(v){
13776 return !v ? v : String(v).replace(this.stripTagsRE, "");
13780 Roo.util.Format.defaults = {
13784 * Ext JS Library 1.1.1
13785 * Copyright(c) 2006-2007, Ext JS, LLC.
13787 * Originally Released Under LGPL - original licence link has changed is not relivant.
13790 * <script type="text/javascript">
13797 * @class Roo.MasterTemplate
13798 * @extends Roo.Template
13799 * Provides a template that can have child templates. The syntax is:
13801 var t = new Roo.MasterTemplate(
13802 '<select name="{name}">',
13803 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13806 t.add('options', {value: 'foo', text: 'bar'});
13807 // or you can add multiple child elements in one shot
13808 t.addAll('options', [
13809 {value: 'foo', text: 'bar'},
13810 {value: 'foo2', text: 'bar2'},
13811 {value: 'foo3', text: 'bar3'}
13813 // then append, applying the master template values
13814 t.append('my-form', {name: 'my-select'});
13816 * A name attribute for the child template is not required if you have only one child
13817 * template or you want to refer to them by index.
13819 Roo.MasterTemplate = function(){
13820 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13821 this.originalHtml = this.html;
13823 var m, re = this.subTemplateRe;
13826 while(m = re.exec(this.html)){
13827 var name = m[1], content = m[2];
13832 tpl : new Roo.Template(content)
13835 st[name] = st[subIndex];
13837 st[subIndex].tpl.compile();
13838 st[subIndex].tpl.call = this.call.createDelegate(this);
13841 this.subCount = subIndex;
13844 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13846 * The regular expression used to match sub templates
13850 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13853 * Applies the passed values to a child template.
13854 * @param {String/Number} name (optional) The name or index of the child template
13855 * @param {Array/Object} values The values to be applied to the template
13856 * @return {MasterTemplate} this
13858 add : function(name, values){
13859 if(arguments.length == 1){
13860 values = arguments[0];
13863 var s = this.subs[name];
13864 s.buffer[s.buffer.length] = s.tpl.apply(values);
13869 * Applies all the passed values to a child template.
13870 * @param {String/Number} name (optional) The name or index of the child template
13871 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13872 * @param {Boolean} reset (optional) True to reset the template first
13873 * @return {MasterTemplate} this
13875 fill : function(name, values, reset){
13877 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13885 for(var i = 0, len = values.length; i < len; i++){
13886 this.add(name, values[i]);
13892 * Resets the template for reuse
13893 * @return {MasterTemplate} this
13895 reset : function(){
13897 for(var i = 0; i < this.subCount; i++){
13903 applyTemplate : function(values){
13905 var replaceIndex = -1;
13906 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13907 return s[++replaceIndex].buffer.join("");
13909 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13912 apply : function(){
13913 return this.applyTemplate.apply(this, arguments);
13916 compile : function(){return this;}
13920 * Alias for fill().
13923 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13925 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13926 * var tpl = Roo.MasterTemplate.from('element-id');
13927 * @param {String/HTMLElement} el
13928 * @param {Object} config
13931 Roo.MasterTemplate.from = function(el, config){
13932 el = Roo.getDom(el);
13933 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13936 * Ext JS Library 1.1.1
13937 * Copyright(c) 2006-2007, Ext JS, LLC.
13939 * Originally Released Under LGPL - original licence link has changed is not relivant.
13942 * <script type="text/javascript">
13947 * @class Roo.util.CSS
13948 * Utility class for manipulating CSS rules
13951 Roo.util.CSS = function(){
13953 var doc = document;
13955 var camelRe = /(-[a-z])/gi;
13956 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13960 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13961 * tag and appended to the HEAD of the document.
13962 * @param {String|Object} cssText The text containing the css rules
13963 * @param {String} id An id to add to the stylesheet for later removal
13964 * @return {StyleSheet}
13966 createStyleSheet : function(cssText, id){
13968 var head = doc.getElementsByTagName("head")[0];
13969 var nrules = doc.createElement("style");
13970 nrules.setAttribute("type", "text/css");
13972 nrules.setAttribute("id", id);
13974 if (typeof(cssText) != 'string') {
13975 // support object maps..
13976 // not sure if this a good idea..
13977 // perhaps it should be merged with the general css handling
13978 // and handle js style props.
13979 var cssTextNew = [];
13980 for(var n in cssText) {
13982 for(var k in cssText[n]) {
13983 citems.push( k + ' : ' +cssText[n][k] + ';' );
13985 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13988 cssText = cssTextNew.join("\n");
13994 head.appendChild(nrules);
13995 ss = nrules.styleSheet;
13996 ss.cssText = cssText;
13999 nrules.appendChild(doc.createTextNode(cssText));
14001 nrules.cssText = cssText;
14003 head.appendChild(nrules);
14004 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14006 this.cacheStyleSheet(ss);
14011 * Removes a style or link tag by id
14012 * @param {String} id The id of the tag
14014 removeStyleSheet : function(id){
14015 var existing = doc.getElementById(id);
14017 existing.parentNode.removeChild(existing);
14022 * Dynamically swaps an existing stylesheet reference for a new one
14023 * @param {String} id The id of an existing link tag to remove
14024 * @param {String} url The href of the new stylesheet to include
14026 swapStyleSheet : function(id, url){
14027 this.removeStyleSheet(id);
14028 var ss = doc.createElement("link");
14029 ss.setAttribute("rel", "stylesheet");
14030 ss.setAttribute("type", "text/css");
14031 ss.setAttribute("id", id);
14032 ss.setAttribute("href", url);
14033 doc.getElementsByTagName("head")[0].appendChild(ss);
14037 * Refresh the rule cache if you have dynamically added stylesheets
14038 * @return {Object} An object (hash) of rules indexed by selector
14040 refreshCache : function(){
14041 return this.getRules(true);
14045 cacheStyleSheet : function(stylesheet){
14049 try{// try catch for cross domain access issue
14050 var ssRules = stylesheet.cssRules || stylesheet.rules;
14051 for(var j = ssRules.length-1; j >= 0; --j){
14052 rules[ssRules[j].selectorText] = ssRules[j];
14058 * Gets all css rules for the document
14059 * @param {Boolean} refreshCache true to refresh the internal cache
14060 * @return {Object} An object (hash) of rules indexed by selector
14062 getRules : function(refreshCache){
14063 if(rules == null || refreshCache){
14065 var ds = doc.styleSheets;
14066 for(var i =0, len = ds.length; i < len; i++){
14068 this.cacheStyleSheet(ds[i]);
14076 * Gets an an individual CSS rule by selector(s)
14077 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14078 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14079 * @return {CSSRule} The CSS rule or null if one is not found
14081 getRule : function(selector, refreshCache){
14082 var rs = this.getRules(refreshCache);
14083 if(!(selector instanceof Array)){
14084 return rs[selector];
14086 for(var i = 0; i < selector.length; i++){
14087 if(rs[selector[i]]){
14088 return rs[selector[i]];
14096 * Updates a rule property
14097 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14098 * @param {String} property The css property
14099 * @param {String} value The new value for the property
14100 * @return {Boolean} true If a rule was found and updated
14102 updateRule : function(selector, property, value){
14103 if(!(selector instanceof Array)){
14104 var rule = this.getRule(selector);
14106 rule.style[property.replace(camelRe, camelFn)] = value;
14110 for(var i = 0; i < selector.length; i++){
14111 if(this.updateRule(selector[i], property, value)){
14121 * Ext JS Library 1.1.1
14122 * Copyright(c) 2006-2007, Ext JS, LLC.
14124 * Originally Released Under LGPL - original licence link has changed is not relivant.
14127 * <script type="text/javascript">
14133 * @class Roo.util.ClickRepeater
14134 * @extends Roo.util.Observable
14136 * A wrapper class which can be applied to any element. Fires a "click" event while the
14137 * mouse is pressed. The interval between firings may be specified in the config but
14138 * defaults to 10 milliseconds.
14140 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14142 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14143 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14144 * Similar to an autorepeat key delay.
14145 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14146 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14147 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14148 * "interval" and "delay" are ignored. "immediate" is honored.
14149 * @cfg {Boolean} preventDefault True to prevent the default click event
14150 * @cfg {Boolean} stopDefault True to stop the default click event
14153 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14154 * 2007-02-02 jvs Renamed to ClickRepeater
14155 * 2007-02-03 jvs Modifications for FF Mac and Safari
14158 * @param {String/HTMLElement/Element} el The element to listen on
14159 * @param {Object} config
14161 Roo.util.ClickRepeater = function(el, config)
14163 this.el = Roo.get(el);
14164 this.el.unselectable();
14166 Roo.apply(this, config);
14171 * Fires when the mouse button is depressed.
14172 * @param {Roo.util.ClickRepeater} this
14174 "mousedown" : true,
14177 * Fires on a specified interval during the time the element is pressed.
14178 * @param {Roo.util.ClickRepeater} this
14183 * Fires when the mouse key is released.
14184 * @param {Roo.util.ClickRepeater} this
14189 this.el.on("mousedown", this.handleMouseDown, this);
14190 if(this.preventDefault || this.stopDefault){
14191 this.el.on("click", function(e){
14192 if(this.preventDefault){
14193 e.preventDefault();
14195 if(this.stopDefault){
14201 // allow inline handler
14203 this.on("click", this.handler, this.scope || this);
14206 Roo.util.ClickRepeater.superclass.constructor.call(this);
14209 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14212 preventDefault : true,
14213 stopDefault : false,
14217 handleMouseDown : function(){
14218 clearTimeout(this.timer);
14220 if(this.pressClass){
14221 this.el.addClass(this.pressClass);
14223 this.mousedownTime = new Date();
14225 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14226 this.el.on("mouseout", this.handleMouseOut, this);
14228 this.fireEvent("mousedown", this);
14229 this.fireEvent("click", this);
14231 this.timer = this.click.defer(this.delay || this.interval, this);
14235 click : function(){
14236 this.fireEvent("click", this);
14237 this.timer = this.click.defer(this.getInterval(), this);
14241 getInterval: function(){
14242 if(!this.accelerate){
14243 return this.interval;
14245 var pressTime = this.mousedownTime.getElapsed();
14246 if(pressTime < 500){
14248 }else if(pressTime < 1700){
14250 }else if(pressTime < 2600){
14252 }else if(pressTime < 3500){
14254 }else if(pressTime < 4400){
14256 }else if(pressTime < 5300){
14258 }else if(pressTime < 6200){
14266 handleMouseOut : function(){
14267 clearTimeout(this.timer);
14268 if(this.pressClass){
14269 this.el.removeClass(this.pressClass);
14271 this.el.on("mouseover", this.handleMouseReturn, this);
14275 handleMouseReturn : function(){
14276 this.el.un("mouseover", this.handleMouseReturn);
14277 if(this.pressClass){
14278 this.el.addClass(this.pressClass);
14284 handleMouseUp : function(){
14285 clearTimeout(this.timer);
14286 this.el.un("mouseover", this.handleMouseReturn);
14287 this.el.un("mouseout", this.handleMouseOut);
14288 Roo.get(document).un("mouseup", this.handleMouseUp);
14289 this.el.removeClass(this.pressClass);
14290 this.fireEvent("mouseup", this);
14294 * Ext JS Library 1.1.1
14295 * Copyright(c) 2006-2007, Ext JS, LLC.
14297 * Originally Released Under LGPL - original licence link has changed is not relivant.
14300 * <script type="text/javascript">
14305 * @class Roo.KeyNav
14306 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14307 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14308 * way to implement custom navigation schemes for any UI component.</p>
14309 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14310 * pageUp, pageDown, del, home, end. Usage:</p>
14312 var nav = new Roo.KeyNav("my-element", {
14313 "left" : function(e){
14314 this.moveLeft(e.ctrlKey);
14316 "right" : function(e){
14317 this.moveRight(e.ctrlKey);
14319 "enter" : function(e){
14326 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14327 * @param {Object} config The config
14329 Roo.KeyNav = function(el, config){
14330 this.el = Roo.get(el);
14331 Roo.apply(this, config);
14332 if(!this.disabled){
14333 this.disabled = true;
14338 Roo.KeyNav.prototype = {
14340 * @cfg {Boolean} disabled
14341 * True to disable this KeyNav instance (defaults to false)
14345 * @cfg {String} defaultEventAction
14346 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14347 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14348 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14350 defaultEventAction: "stopEvent",
14352 * @cfg {Boolean} forceKeyDown
14353 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14354 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14355 * handle keydown instead of keypress.
14357 forceKeyDown : false,
14360 prepareEvent : function(e){
14361 var k = e.getKey();
14362 var h = this.keyToHandler[k];
14363 //if(h && this[h]){
14364 // e.stopPropagation();
14366 if(Roo.isSafari && h && k >= 37 && k <= 40){
14372 relay : function(e){
14373 var k = e.getKey();
14374 var h = this.keyToHandler[k];
14376 if(this.doRelay(e, this[h], h) !== true){
14377 e[this.defaultEventAction]();
14383 doRelay : function(e, h, hname){
14384 return h.call(this.scope || this, e);
14387 // possible handlers
14401 // quick lookup hash
14418 * Enable this KeyNav
14420 enable: function(){
14422 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14423 // the EventObject will normalize Safari automatically
14424 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14425 this.el.on("keydown", this.relay, this);
14427 this.el.on("keydown", this.prepareEvent, this);
14428 this.el.on("keypress", this.relay, this);
14430 this.disabled = false;
14435 * Disable this KeyNav
14437 disable: function(){
14438 if(!this.disabled){
14439 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14440 this.el.un("keydown", this.relay);
14442 this.el.un("keydown", this.prepareEvent);
14443 this.el.un("keypress", this.relay);
14445 this.disabled = true;
14450 * Ext JS Library 1.1.1
14451 * Copyright(c) 2006-2007, Ext JS, LLC.
14453 * Originally Released Under LGPL - original licence link has changed is not relivant.
14456 * <script type="text/javascript">
14461 * @class Roo.KeyMap
14462 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14463 * The constructor accepts the same config object as defined by {@link #addBinding}.
14464 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14465 * combination it will call the function with this signature (if the match is a multi-key
14466 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14467 * A KeyMap can also handle a string representation of keys.<br />
14470 // map one key by key code
14471 var map = new Roo.KeyMap("my-element", {
14472 key: 13, // or Roo.EventObject.ENTER
14477 // map multiple keys to one action by string
14478 var map = new Roo.KeyMap("my-element", {
14484 // map multiple keys to multiple actions by strings and array of codes
14485 var map = new Roo.KeyMap("my-element", [
14488 fn: function(){ alert("Return was pressed"); }
14491 fn: function(){ alert('a, b or c was pressed'); }
14496 fn: function(){ alert('Control + shift + tab was pressed.'); }
14500 * <b>Note: A KeyMap starts enabled</b>
14502 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14503 * @param {Object} config The config (see {@link #addBinding})
14504 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14506 Roo.KeyMap = function(el, config, eventName){
14507 this.el = Roo.get(el);
14508 this.eventName = eventName || "keydown";
14509 this.bindings = [];
14511 this.addBinding(config);
14516 Roo.KeyMap.prototype = {
14518 * True to stop the event from bubbling and prevent the default browser action if the
14519 * key was handled by the KeyMap (defaults to false)
14525 * Add a new binding to this KeyMap. The following config object properties are supported:
14527 Property Type Description
14528 ---------- --------------- ----------------------------------------------------------------------
14529 key String/Array A single keycode or an array of keycodes to handle
14530 shift Boolean True to handle key only when shift is pressed (defaults to false)
14531 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14532 alt Boolean True to handle key only when alt is pressed (defaults to false)
14533 fn Function The function to call when KeyMap finds the expected key combination
14534 scope Object The scope of the callback function
14540 var map = new Roo.KeyMap(document, {
14541 key: Roo.EventObject.ENTER,
14546 //Add a new binding to the existing KeyMap later
14554 * @param {Object/Array} config A single KeyMap config or an array of configs
14556 addBinding : function(config){
14557 if(config instanceof Array){
14558 for(var i = 0, len = config.length; i < len; i++){
14559 this.addBinding(config[i]);
14563 var keyCode = config.key,
14564 shift = config.shift,
14565 ctrl = config.ctrl,
14568 scope = config.scope;
14569 if(typeof keyCode == "string"){
14571 var keyString = keyCode.toUpperCase();
14572 for(var j = 0, len = keyString.length; j < len; j++){
14573 ks.push(keyString.charCodeAt(j));
14577 var keyArray = keyCode instanceof Array;
14578 var handler = function(e){
14579 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14580 var k = e.getKey();
14582 for(var i = 0, len = keyCode.length; i < len; i++){
14583 if(keyCode[i] == k){
14584 if(this.stopEvent){
14587 fn.call(scope || window, k, e);
14593 if(this.stopEvent){
14596 fn.call(scope || window, k, e);
14601 this.bindings.push(handler);
14605 * Shorthand for adding a single key listener
14606 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14607 * following options:
14608 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14609 * @param {Function} fn The function to call
14610 * @param {Object} scope (optional) The scope of the function
14612 on : function(key, fn, scope){
14613 var keyCode, shift, ctrl, alt;
14614 if(typeof key == "object" && !(key instanceof Array)){
14633 handleKeyDown : function(e){
14634 if(this.enabled){ //just in case
14635 var b = this.bindings;
14636 for(var i = 0, len = b.length; i < len; i++){
14637 b[i].call(this, e);
14643 * Returns true if this KeyMap is enabled
14644 * @return {Boolean}
14646 isEnabled : function(){
14647 return this.enabled;
14651 * Enables this KeyMap
14653 enable: function(){
14655 this.el.on(this.eventName, this.handleKeyDown, this);
14656 this.enabled = true;
14661 * Disable this KeyMap
14663 disable: function(){
14665 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14666 this.enabled = false;
14671 * Ext JS Library 1.1.1
14672 * Copyright(c) 2006-2007, Ext JS, LLC.
14674 * Originally Released Under LGPL - original licence link has changed is not relivant.
14677 * <script type="text/javascript">
14682 * @class Roo.util.TextMetrics
14683 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14684 * wide, in pixels, a given block of text will be.
14687 Roo.util.TextMetrics = function(){
14691 * Measures the size of the specified text
14692 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14693 * that can affect the size of the rendered text
14694 * @param {String} text The text to measure
14695 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14696 * in order to accurately measure the text height
14697 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14699 measure : function(el, text, fixedWidth){
14701 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14704 shared.setFixedWidth(fixedWidth || 'auto');
14705 return shared.getSize(text);
14709 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14710 * the overhead of multiple calls to initialize the style properties on each measurement.
14711 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14712 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14713 * in order to accurately measure the text height
14714 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14716 createInstance : function(el, fixedWidth){
14717 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14724 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14725 var ml = new Roo.Element(document.createElement('div'));
14726 document.body.appendChild(ml.dom);
14727 ml.position('absolute');
14728 ml.setLeftTop(-1000, -1000);
14732 ml.setWidth(fixedWidth);
14737 * Returns the size of the specified text based on the internal element's style and width properties
14738 * @memberOf Roo.util.TextMetrics.Instance#
14739 * @param {String} text The text to measure
14740 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14742 getSize : function(text){
14744 var s = ml.getSize();
14750 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14751 * that can affect the size of the rendered text
14752 * @memberOf Roo.util.TextMetrics.Instance#
14753 * @param {String/HTMLElement} el The element, dom node or id
14755 bind : function(el){
14757 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14762 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14763 * to set a fixed width in order to accurately measure the text height.
14764 * @memberOf Roo.util.TextMetrics.Instance#
14765 * @param {Number} width The width to set on the element
14767 setFixedWidth : function(width){
14768 ml.setWidth(width);
14772 * Returns the measured width of the specified text
14773 * @memberOf Roo.util.TextMetrics.Instance#
14774 * @param {String} text The text to measure
14775 * @return {Number} width The width in pixels
14777 getWidth : function(text){
14778 ml.dom.style.width = 'auto';
14779 return this.getSize(text).width;
14783 * Returns the measured height of the specified text. For multiline text, be sure to call
14784 * {@link #setFixedWidth} if necessary.
14785 * @memberOf Roo.util.TextMetrics.Instance#
14786 * @param {String} text The text to measure
14787 * @return {Number} height The height in pixels
14789 getHeight : function(text){
14790 return this.getSize(text).height;
14794 instance.bind(bindTo);
14799 // backwards compat
14800 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14802 * Ext JS Library 1.1.1
14803 * Copyright(c) 2006-2007, Ext JS, LLC.
14805 * Originally Released Under LGPL - original licence link has changed is not relivant.
14808 * <script type="text/javascript">
14812 * @class Roo.state.Provider
14813 * Abstract base class for state provider implementations. This class provides methods
14814 * for encoding and decoding <b>typed</b> variables including dates and defines the
14815 * Provider interface.
14817 Roo.state.Provider = function(){
14819 * @event statechange
14820 * Fires when a state change occurs.
14821 * @param {Provider} this This state provider
14822 * @param {String} key The state key which was changed
14823 * @param {String} value The encoded value for the state
14826 "statechange": true
14829 Roo.state.Provider.superclass.constructor.call(this);
14831 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14833 * Returns the current value for a key
14834 * @param {String} name The key name
14835 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14836 * @return {Mixed} The state data
14838 get : function(name, defaultValue){
14839 return typeof this.state[name] == "undefined" ?
14840 defaultValue : this.state[name];
14844 * Clears a value from the state
14845 * @param {String} name The key name
14847 clear : function(name){
14848 delete this.state[name];
14849 this.fireEvent("statechange", this, name, null);
14853 * Sets the value for a key
14854 * @param {String} name The key name
14855 * @param {Mixed} value The value to set
14857 set : function(name, value){
14858 this.state[name] = value;
14859 this.fireEvent("statechange", this, name, value);
14863 * Decodes a string previously encoded with {@link #encodeValue}.
14864 * @param {String} value The value to decode
14865 * @return {Mixed} The decoded value
14867 decodeValue : function(cookie){
14868 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14869 var matches = re.exec(unescape(cookie));
14870 if(!matches || !matches[1]) {
14871 return; // non state cookie
14873 var type = matches[1];
14874 var v = matches[2];
14877 return parseFloat(v);
14879 return new Date(Date.parse(v));
14884 var values = v.split("^");
14885 for(var i = 0, len = values.length; i < len; i++){
14886 all.push(this.decodeValue(values[i]));
14891 var values = v.split("^");
14892 for(var i = 0, len = values.length; i < len; i++){
14893 var kv = values[i].split("=");
14894 all[kv[0]] = this.decodeValue(kv[1]);
14903 * Encodes a value including type information. Decode with {@link #decodeValue}.
14904 * @param {Mixed} value The value to encode
14905 * @return {String} The encoded value
14907 encodeValue : function(v){
14909 if(typeof v == "number"){
14911 }else if(typeof v == "boolean"){
14912 enc = "b:" + (v ? "1" : "0");
14913 }else if(v instanceof Date){
14914 enc = "d:" + v.toGMTString();
14915 }else if(v instanceof Array){
14917 for(var i = 0, len = v.length; i < len; i++){
14918 flat += this.encodeValue(v[i]);
14924 }else if(typeof v == "object"){
14927 if(typeof v[key] != "function"){
14928 flat += key + "=" + this.encodeValue(v[key]) + "^";
14931 enc = "o:" + flat.substring(0, flat.length-1);
14935 return escape(enc);
14941 * Ext JS Library 1.1.1
14942 * Copyright(c) 2006-2007, Ext JS, LLC.
14944 * Originally Released Under LGPL - original licence link has changed is not relivant.
14947 * <script type="text/javascript">
14950 * @class Roo.state.Manager
14951 * This is the global state manager. By default all components that are "state aware" check this class
14952 * for state information if you don't pass them a custom state provider. In order for this class
14953 * to be useful, it must be initialized with a provider when your application initializes.
14955 // in your initialization function
14957 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14959 // supposed you have a {@link Roo.BorderLayout}
14960 var layout = new Roo.BorderLayout(...);
14961 layout.restoreState();
14962 // or a {Roo.BasicDialog}
14963 var dialog = new Roo.BasicDialog(...);
14964 dialog.restoreState();
14968 Roo.state.Manager = function(){
14969 var provider = new Roo.state.Provider();
14973 * Configures the default state provider for your application
14974 * @param {Provider} stateProvider The state provider to set
14976 setProvider : function(stateProvider){
14977 provider = stateProvider;
14981 * Returns the current value for a key
14982 * @param {String} name The key name
14983 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14984 * @return {Mixed} The state data
14986 get : function(key, defaultValue){
14987 return provider.get(key, defaultValue);
14991 * Sets the value for a key
14992 * @param {String} name The key name
14993 * @param {Mixed} value The state data
14995 set : function(key, value){
14996 provider.set(key, value);
15000 * Clears a value from the state
15001 * @param {String} name The key name
15003 clear : function(key){
15004 provider.clear(key);
15008 * Gets the currently configured state provider
15009 * @return {Provider} The state provider
15011 getProvider : function(){
15018 * Ext JS Library 1.1.1
15019 * Copyright(c) 2006-2007, Ext JS, LLC.
15021 * Originally Released Under LGPL - original licence link has changed is not relivant.
15024 * <script type="text/javascript">
15027 * @class Roo.state.CookieProvider
15028 * @extends Roo.state.Provider
15029 * The default Provider implementation which saves state via cookies.
15032 var cp = new Roo.state.CookieProvider({
15034 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15035 domain: "roojs.com"
15037 Roo.state.Manager.setProvider(cp);
15039 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15040 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15041 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15042 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15043 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15044 * domain the page is running on including the 'www' like 'www.roojs.com')
15045 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15047 * Create a new CookieProvider
15048 * @param {Object} config The configuration object
15050 Roo.state.CookieProvider = function(config){
15051 Roo.state.CookieProvider.superclass.constructor.call(this);
15053 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15054 this.domain = null;
15055 this.secure = false;
15056 Roo.apply(this, config);
15057 this.state = this.readCookies();
15060 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15062 set : function(name, value){
15063 if(typeof value == "undefined" || value === null){
15067 this.setCookie(name, value);
15068 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15072 clear : function(name){
15073 this.clearCookie(name);
15074 Roo.state.CookieProvider.superclass.clear.call(this, name);
15078 readCookies : function(){
15080 var c = document.cookie + ";";
15081 var re = /\s?(.*?)=(.*?);/g;
15083 while((matches = re.exec(c)) != null){
15084 var name = matches[1];
15085 var value = matches[2];
15086 if(name && name.substring(0,3) == "ys-"){
15087 cookies[name.substr(3)] = this.decodeValue(value);
15094 setCookie : function(name, value){
15095 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15096 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15097 ((this.path == null) ? "" : ("; path=" + this.path)) +
15098 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15099 ((this.secure == true) ? "; secure" : "");
15103 clearCookie : function(name){
15104 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15105 ((this.path == null) ? "" : ("; path=" + this.path)) +
15106 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15107 ((this.secure == true) ? "; secure" : "");
15111 * Ext JS Library 1.1.1
15112 * Copyright(c) 2006-2007, Ext JS, LLC.
15114 * Originally Released Under LGPL - original licence link has changed is not relivant.
15117 * <script type="text/javascript">
15122 * @class Roo.ComponentMgr
15123 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15126 Roo.ComponentMgr = function(){
15127 var all = new Roo.util.MixedCollection();
15131 * Registers a component.
15132 * @param {Roo.Component} c The component
15134 register : function(c){
15139 * Unregisters a component.
15140 * @param {Roo.Component} c The component
15142 unregister : function(c){
15147 * Returns a component by id
15148 * @param {String} id The component id
15150 get : function(id){
15151 return all.get(id);
15155 * Registers a function that will be called when a specified component is added to ComponentMgr
15156 * @param {String} id The component id
15157 * @param {Funtction} fn The callback function
15158 * @param {Object} scope The scope of the callback
15160 onAvailable : function(id, fn, scope){
15161 all.on("add", function(index, o){
15163 fn.call(scope || o, o);
15164 all.un("add", fn, scope);
15171 * Ext JS Library 1.1.1
15172 * Copyright(c) 2006-2007, Ext JS, LLC.
15174 * Originally Released Under LGPL - original licence link has changed is not relivant.
15177 * <script type="text/javascript">
15181 * @class Roo.Component
15182 * @extends Roo.util.Observable
15183 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15184 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15185 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15186 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15187 * All visual components (widgets) that require rendering into a layout should subclass Component.
15189 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15190 * 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
15191 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15193 Roo.Component = function(config){
15194 config = config || {};
15195 if(config.tagName || config.dom || typeof config == "string"){ // element object
15196 config = {el: config, id: config.id || config};
15198 this.initialConfig = config;
15200 Roo.apply(this, config);
15204 * Fires after the component is disabled.
15205 * @param {Roo.Component} this
15210 * Fires after the component is enabled.
15211 * @param {Roo.Component} this
15215 * @event beforeshow
15216 * Fires before the component is shown. Return false to stop the show.
15217 * @param {Roo.Component} this
15222 * Fires after the component is shown.
15223 * @param {Roo.Component} this
15227 * @event beforehide
15228 * Fires before the component is hidden. Return false to stop the hide.
15229 * @param {Roo.Component} this
15234 * Fires after the component is hidden.
15235 * @param {Roo.Component} this
15239 * @event beforerender
15240 * Fires before the component is rendered. Return false to stop the render.
15241 * @param {Roo.Component} this
15243 beforerender : true,
15246 * Fires after the component is rendered.
15247 * @param {Roo.Component} this
15251 * @event beforedestroy
15252 * Fires before the component is destroyed. Return false to stop the destroy.
15253 * @param {Roo.Component} this
15255 beforedestroy : true,
15258 * Fires after the component is destroyed.
15259 * @param {Roo.Component} this
15264 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15266 Roo.ComponentMgr.register(this);
15267 Roo.Component.superclass.constructor.call(this);
15268 this.initComponent();
15269 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15270 this.render(this.renderTo);
15271 delete this.renderTo;
15276 Roo.Component.AUTO_ID = 1000;
15278 Roo.extend(Roo.Component, Roo.util.Observable, {
15280 * @scope Roo.Component.prototype
15282 * true if this component is hidden. Read-only.
15287 * true if this component is disabled. Read-only.
15292 * true if this component has been rendered. Read-only.
15296 /** @cfg {String} disableClass
15297 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15299 disabledClass : "x-item-disabled",
15300 /** @cfg {Boolean} allowDomMove
15301 * Whether the component can move the Dom node when rendering (defaults to true).
15303 allowDomMove : true,
15304 /** @cfg {String} hideMode (display|visibility)
15305 * How this component should hidden. Supported values are
15306 * "visibility" (css visibility), "offsets" (negative offset position) and
15307 * "display" (css display) - defaults to "display".
15309 hideMode: 'display',
15312 ctype : "Roo.Component",
15315 * @cfg {String} actionMode
15316 * which property holds the element that used for hide() / show() / disable() / enable()
15322 getActionEl : function(){
15323 return this[this.actionMode];
15326 initComponent : Roo.emptyFn,
15328 * If this is a lazy rendering component, render it to its container element.
15329 * @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.
15331 render : function(container, position){
15332 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15333 if(!container && this.el){
15334 this.el = Roo.get(this.el);
15335 container = this.el.dom.parentNode;
15336 this.allowDomMove = false;
15338 this.container = Roo.get(container);
15339 this.rendered = true;
15340 if(position !== undefined){
15341 if(typeof position == 'number'){
15342 position = this.container.dom.childNodes[position];
15344 position = Roo.getDom(position);
15347 this.onRender(this.container, position || null);
15349 this.el.addClass(this.cls);
15353 this.el.applyStyles(this.style);
15356 this.fireEvent("render", this);
15357 this.afterRender(this.container);
15369 // default function is not really useful
15370 onRender : function(ct, position){
15372 this.el = Roo.get(this.el);
15373 if(this.allowDomMove !== false){
15374 ct.dom.insertBefore(this.el.dom, position);
15380 getAutoCreate : function(){
15381 var cfg = typeof this.autoCreate == "object" ?
15382 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15383 if(this.id && !cfg.id){
15390 afterRender : Roo.emptyFn,
15393 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15394 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15396 destroy : function(){
15397 if(this.fireEvent("beforedestroy", this) !== false){
15398 this.purgeListeners();
15399 this.beforeDestroy();
15401 this.el.removeAllListeners();
15403 if(this.actionMode == "container"){
15404 this.container.remove();
15408 Roo.ComponentMgr.unregister(this);
15409 this.fireEvent("destroy", this);
15414 beforeDestroy : function(){
15419 onDestroy : function(){
15424 * Returns the underlying {@link Roo.Element}.
15425 * @return {Roo.Element} The element
15427 getEl : function(){
15432 * Returns the id of this component.
15435 getId : function(){
15440 * Try to focus this component.
15441 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15442 * @return {Roo.Component} this
15444 focus : function(selectText){
15447 if(selectText === true){
15448 this.el.dom.select();
15463 * Disable this component.
15464 * @return {Roo.Component} this
15466 disable : function(){
15470 this.disabled = true;
15471 this.fireEvent("disable", this);
15476 onDisable : function(){
15477 this.getActionEl().addClass(this.disabledClass);
15478 this.el.dom.disabled = true;
15482 * Enable this component.
15483 * @return {Roo.Component} this
15485 enable : function(){
15489 this.disabled = false;
15490 this.fireEvent("enable", this);
15495 onEnable : function(){
15496 this.getActionEl().removeClass(this.disabledClass);
15497 this.el.dom.disabled = false;
15501 * Convenience function for setting disabled/enabled by boolean.
15502 * @param {Boolean} disabled
15504 setDisabled : function(disabled){
15505 this[disabled ? "disable" : "enable"]();
15509 * Show this component.
15510 * @return {Roo.Component} this
15513 if(this.fireEvent("beforeshow", this) !== false){
15514 this.hidden = false;
15518 this.fireEvent("show", this);
15524 onShow : function(){
15525 var ae = this.getActionEl();
15526 if(this.hideMode == 'visibility'){
15527 ae.dom.style.visibility = "visible";
15528 }else if(this.hideMode == 'offsets'){
15529 ae.removeClass('x-hidden');
15531 ae.dom.style.display = "";
15536 * Hide this component.
15537 * @return {Roo.Component} this
15540 if(this.fireEvent("beforehide", this) !== false){
15541 this.hidden = true;
15545 this.fireEvent("hide", this);
15551 onHide : function(){
15552 var ae = this.getActionEl();
15553 if(this.hideMode == 'visibility'){
15554 ae.dom.style.visibility = "hidden";
15555 }else if(this.hideMode == 'offsets'){
15556 ae.addClass('x-hidden');
15558 ae.dom.style.display = "none";
15563 * Convenience function to hide or show this component by boolean.
15564 * @param {Boolean} visible True to show, false to hide
15565 * @return {Roo.Component} this
15567 setVisible: function(visible){
15577 * Returns true if this component is visible.
15579 isVisible : function(){
15580 return this.getActionEl().isVisible();
15583 cloneConfig : function(overrides){
15584 overrides = overrides || {};
15585 var id = overrides.id || Roo.id();
15586 var cfg = Roo.applyIf(overrides, this.initialConfig);
15587 cfg.id = id; // prevent dup id
15588 return new this.constructor(cfg);
15592 * Ext JS Library 1.1.1
15593 * Copyright(c) 2006-2007, Ext JS, LLC.
15595 * Originally Released Under LGPL - original licence link has changed is not relivant.
15598 * <script type="text/javascript">
15602 * @class Roo.BoxComponent
15603 * @extends Roo.Component
15604 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15605 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15606 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15607 * layout containers.
15609 * @param {Roo.Element/String/Object} config The configuration options.
15611 Roo.BoxComponent = function(config){
15612 Roo.Component.call(this, config);
15616 * Fires after the component is resized.
15617 * @param {Roo.Component} this
15618 * @param {Number} adjWidth The box-adjusted width that was set
15619 * @param {Number} adjHeight The box-adjusted height that was set
15620 * @param {Number} rawWidth The width that was originally specified
15621 * @param {Number} rawHeight The height that was originally specified
15626 * Fires after the component is moved.
15627 * @param {Roo.Component} this
15628 * @param {Number} x The new x position
15629 * @param {Number} y The new y position
15635 Roo.extend(Roo.BoxComponent, Roo.Component, {
15636 // private, set in afterRender to signify that the component has been rendered
15638 // private, used to defer height settings to subclasses
15639 deferHeight: false,
15640 /** @cfg {Number} width
15641 * width (optional) size of component
15643 /** @cfg {Number} height
15644 * height (optional) size of component
15648 * Sets the width and height of the component. This method fires the resize event. This method can accept
15649 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15650 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15651 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15652 * @return {Roo.BoxComponent} this
15654 setSize : function(w, h){
15655 // support for standard size objects
15656 if(typeof w == 'object'){
15661 if(!this.boxReady){
15667 // prevent recalcs when not needed
15668 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15671 this.lastSize = {width: w, height: h};
15673 var adj = this.adjustSize(w, h);
15674 var aw = adj.width, ah = adj.height;
15675 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15676 var rz = this.getResizeEl();
15677 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15678 rz.setSize(aw, ah);
15679 }else if(!this.deferHeight && ah !== undefined){
15681 }else if(aw !== undefined){
15684 this.onResize(aw, ah, w, h);
15685 this.fireEvent('resize', this, aw, ah, w, h);
15691 * Gets the current size of the component's underlying element.
15692 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15694 getSize : function(){
15695 return this.el.getSize();
15699 * Gets the current XY position of the component's underlying element.
15700 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15701 * @return {Array} The XY position of the element (e.g., [100, 200])
15703 getPosition : function(local){
15704 if(local === true){
15705 return [this.el.getLeft(true), this.el.getTop(true)];
15707 return this.xy || this.el.getXY();
15711 * Gets the current box measurements of the component's underlying element.
15712 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15713 * @returns {Object} box An object in the format {x, y, width, height}
15715 getBox : function(local){
15716 var s = this.el.getSize();
15718 s.x = this.el.getLeft(true);
15719 s.y = this.el.getTop(true);
15721 var xy = this.xy || this.el.getXY();
15729 * Sets the current box measurements of the component's underlying element.
15730 * @param {Object} box An object in the format {x, y, width, height}
15731 * @returns {Roo.BoxComponent} this
15733 updateBox : function(box){
15734 this.setSize(box.width, box.height);
15735 this.setPagePosition(box.x, box.y);
15740 getResizeEl : function(){
15741 return this.resizeEl || this.el;
15745 getPositionEl : function(){
15746 return this.positionEl || this.el;
15750 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15751 * This method fires the move event.
15752 * @param {Number} left The new left
15753 * @param {Number} top The new top
15754 * @returns {Roo.BoxComponent} this
15756 setPosition : function(x, y){
15759 if(!this.boxReady){
15762 var adj = this.adjustPosition(x, y);
15763 var ax = adj.x, ay = adj.y;
15765 var el = this.getPositionEl();
15766 if(ax !== undefined || ay !== undefined){
15767 if(ax !== undefined && ay !== undefined){
15768 el.setLeftTop(ax, ay);
15769 }else if(ax !== undefined){
15771 }else if(ay !== undefined){
15774 this.onPosition(ax, ay);
15775 this.fireEvent('move', this, ax, ay);
15781 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15782 * This method fires the move event.
15783 * @param {Number} x The new x position
15784 * @param {Number} y The new y position
15785 * @returns {Roo.BoxComponent} this
15787 setPagePosition : function(x, y){
15790 if(!this.boxReady){
15793 if(x === undefined || y === undefined){ // cannot translate undefined points
15796 var p = this.el.translatePoints(x, y);
15797 this.setPosition(p.left, p.top);
15802 onRender : function(ct, position){
15803 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15805 this.resizeEl = Roo.get(this.resizeEl);
15807 if(this.positionEl){
15808 this.positionEl = Roo.get(this.positionEl);
15813 afterRender : function(){
15814 Roo.BoxComponent.superclass.afterRender.call(this);
15815 this.boxReady = true;
15816 this.setSize(this.width, this.height);
15817 if(this.x || this.y){
15818 this.setPosition(this.x, this.y);
15820 if(this.pageX || this.pageY){
15821 this.setPagePosition(this.pageX, this.pageY);
15826 * Force the component's size to recalculate based on the underlying element's current height and width.
15827 * @returns {Roo.BoxComponent} this
15829 syncSize : function(){
15830 delete this.lastSize;
15831 this.setSize(this.el.getWidth(), this.el.getHeight());
15836 * Called after the component is resized, this method is empty by default but can be implemented by any
15837 * subclass that needs to perform custom logic after a resize occurs.
15838 * @param {Number} adjWidth The box-adjusted width that was set
15839 * @param {Number} adjHeight The box-adjusted height that was set
15840 * @param {Number} rawWidth The width that was originally specified
15841 * @param {Number} rawHeight The height that was originally specified
15843 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15848 * Called after the component is moved, this method is empty by default but can be implemented by any
15849 * subclass that needs to perform custom logic after a move occurs.
15850 * @param {Number} x The new x position
15851 * @param {Number} y The new y position
15853 onPosition : function(x, y){
15858 adjustSize : function(w, h){
15859 if(this.autoWidth){
15862 if(this.autoHeight){
15865 return {width : w, height: h};
15869 adjustPosition : function(x, y){
15870 return {x : x, y: y};
15873 * Original code for Roojs - LGPL
15874 * <script type="text/javascript">
15878 * @class Roo.XComponent
15879 * A delayed Element creator...
15880 * Or a way to group chunks of interface together.
15881 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15882 * used in conjunction with XComponent.build() it will create an instance of each element,
15883 * then call addxtype() to build the User interface.
15885 * Mypart.xyx = new Roo.XComponent({
15887 parent : 'Mypart.xyz', // empty == document.element.!!
15891 disabled : function() {}
15893 tree : function() { // return an tree of xtype declared components
15897 xtype : 'NestedLayoutPanel',
15904 * It can be used to build a big heiracy, with parent etc.
15905 * or you can just use this to render a single compoent to a dom element
15906 * MYPART.render(Roo.Element | String(id) | dom_element )
15913 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15914 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15916 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15918 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15919 * - if mulitple topModules exist, the last one is defined as the top module.
15923 * When the top level or multiple modules are to embedded into a existing HTML page,
15924 * the parent element can container '#id' of the element where the module will be drawn.
15928 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15929 * it relies more on a include mechanism, where sub modules are included into an outer page.
15930 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15932 * Bootstrap Roo Included elements
15934 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15935 * hence confusing the component builder as it thinks there are multiple top level elements.
15939 * @extends Roo.util.Observable
15941 * @param cfg {Object} configuration of component
15944 Roo.XComponent = function(cfg) {
15945 Roo.apply(this, cfg);
15949 * Fires when this the componnt is built
15950 * @param {Roo.XComponent} c the component
15955 this.region = this.region || 'center'; // default..
15956 Roo.XComponent.register(this);
15957 this.modules = false;
15958 this.el = false; // where the layout goes..
15962 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15965 * The created element (with Roo.factory())
15966 * @type {Roo.Layout}
15972 * for BC - use el in new code
15973 * @type {Roo.Layout}
15979 * for BC - use el in new code
15980 * @type {Roo.Layout}
15985 * @cfg {Function|boolean} disabled
15986 * If this module is disabled by some rule, return true from the funtion
15991 * @cfg {String} parent
15992 * Name of parent element which it get xtype added to..
15997 * @cfg {String} order
15998 * Used to set the order in which elements are created (usefull for multiple tabs)
16003 * @cfg {String} name
16004 * String to display while loading.
16008 * @cfg {String} region
16009 * Region to render component to (defaults to center)
16014 * @cfg {Array} items
16015 * A single item array - the first element is the root of the tree..
16016 * It's done this way to stay compatible with the Xtype system...
16022 * The method that retuns the tree of parts that make up this compoennt
16029 * render element to dom or tree
16030 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16033 render : function(el)
16037 var hp = this.parent ? 1 : 0;
16038 Roo.debug && Roo.log(this);
16040 var tree = this._tree ? this._tree() : this.tree();
16043 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16044 // if parent is a '#.....' string, then let's use that..
16045 var ename = this.parent.substr(1);
16046 this.parent = false;
16047 Roo.debug && Roo.log(ename);
16049 case 'bootstrap-body':
16050 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16051 // this is the BorderLayout standard?
16052 this.parent = { el : true };
16055 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16056 // need to insert stuff...
16058 el : new Roo.bootstrap.layout.Border({
16059 el : document.body,
16065 tabPosition: 'top',
16066 //resizeTabs: true,
16067 alwaysShowTabs: true,
16077 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16078 this.parent = { el : new Roo.bootstrap.Body() };
16079 Roo.debug && Roo.log("setting el to doc body");
16082 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16086 this.parent = { el : true};
16089 el = Roo.get(ename);
16090 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16091 this.parent = { el : true};
16098 if (!el && !this.parent) {
16099 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16104 Roo.debug && Roo.log("EL:");
16105 Roo.debug && Roo.log(el);
16106 Roo.debug && Roo.log("this.parent.el:");
16107 Roo.debug && Roo.log(this.parent.el);
16110 // altertive root elements ??? - we need a better way to indicate these.
16111 var is_alt = Roo.XComponent.is_alt ||
16112 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16113 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16114 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16118 if (!this.parent && is_alt) {
16119 //el = Roo.get(document.body);
16120 this.parent = { el : true };
16125 if (!this.parent) {
16127 Roo.debug && Roo.log("no parent - creating one");
16129 el = el ? Roo.get(el) : false;
16131 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16134 el : new Roo.bootstrap.layout.Border({
16135 el: el || document.body,
16141 tabPosition: 'top',
16142 //resizeTabs: true,
16143 alwaysShowTabs: false,
16146 overflow: 'visible'
16152 // it's a top level one..
16154 el : new Roo.BorderLayout(el || document.body, {
16159 tabPosition: 'top',
16160 //resizeTabs: true,
16161 alwaysShowTabs: el && hp? false : true,
16162 hideTabs: el || !hp ? true : false,
16170 if (!this.parent.el) {
16171 // probably an old style ctor, which has been disabled.
16175 // The 'tree' method is '_tree now'
16177 tree.region = tree.region || this.region;
16178 var is_body = false;
16179 if (this.parent.el === true) {
16180 // bootstrap... - body..
16184 this.parent.el = Roo.factory(tree);
16188 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16189 this.fireEvent('built', this);
16191 this.panel = this.el;
16192 this.layout = this.panel.layout;
16193 this.parentLayout = this.parent.layout || false;
16199 Roo.apply(Roo.XComponent, {
16201 * @property hideProgress
16202 * true to disable the building progress bar.. usefull on single page renders.
16205 hideProgress : false,
16207 * @property buildCompleted
16208 * True when the builder has completed building the interface.
16211 buildCompleted : false,
16214 * @property topModule
16215 * the upper most module - uses document.element as it's constructor.
16222 * @property modules
16223 * array of modules to be created by registration system.
16224 * @type {Array} of Roo.XComponent
16229 * @property elmodules
16230 * array of modules to be created by which use #ID
16231 * @type {Array} of Roo.XComponent
16238 * Is an alternative Root - normally used by bootstrap or other systems,
16239 * where the top element in the tree can wrap 'body'
16240 * @type {boolean} (default false)
16245 * @property build_from_html
16246 * Build elements from html - used by bootstrap HTML stuff
16247 * - this is cleared after build is completed
16248 * @type {boolean} (default false)
16251 build_from_html : false,
16253 * Register components to be built later.
16255 * This solves the following issues
16256 * - Building is not done on page load, but after an authentication process has occured.
16257 * - Interface elements are registered on page load
16258 * - Parent Interface elements may not be loaded before child, so this handles that..
16265 module : 'Pman.Tab.projectMgr',
16267 parent : 'Pman.layout',
16268 disabled : false, // or use a function..
16271 * * @param {Object} details about module
16273 register : function(obj) {
16275 Roo.XComponent.event.fireEvent('register', obj);
16276 switch(typeof(obj.disabled) ) {
16282 if ( obj.disabled() ) {
16288 if (obj.disabled) {
16294 this.modules.push(obj);
16298 * convert a string to an object..
16299 * eg. 'AAA.BBB' -> finds AAA.BBB
16303 toObject : function(str)
16305 if (!str || typeof(str) == 'object') {
16308 if (str.substring(0,1) == '#') {
16312 var ar = str.split('.');
16317 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16319 throw "Module not found : " + str;
16323 throw "Module not found : " + str;
16325 Roo.each(ar, function(e) {
16326 if (typeof(o[e]) == 'undefined') {
16327 throw "Module not found : " + str;
16338 * move modules into their correct place in the tree..
16341 preBuild : function ()
16344 Roo.each(this.modules , function (obj)
16346 Roo.XComponent.event.fireEvent('beforebuild', obj);
16348 var opar = obj.parent;
16350 obj.parent = this.toObject(opar);
16352 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16357 Roo.debug && Roo.log("GOT top level module");
16358 Roo.debug && Roo.log(obj);
16359 obj.modules = new Roo.util.MixedCollection(false,
16360 function(o) { return o.order + '' }
16362 this.topModule = obj;
16365 // parent is a string (usually a dom element name..)
16366 if (typeof(obj.parent) == 'string') {
16367 this.elmodules.push(obj);
16370 if (obj.parent.constructor != Roo.XComponent) {
16371 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16373 if (!obj.parent.modules) {
16374 obj.parent.modules = new Roo.util.MixedCollection(false,
16375 function(o) { return o.order + '' }
16378 if (obj.parent.disabled) {
16379 obj.disabled = true;
16381 obj.parent.modules.add(obj);
16386 * make a list of modules to build.
16387 * @return {Array} list of modules.
16390 buildOrder : function()
16393 var cmp = function(a,b) {
16394 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16396 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16397 throw "No top level modules to build";
16400 // make a flat list in order of modules to build.
16401 var mods = this.topModule ? [ this.topModule ] : [];
16404 // elmodules (is a list of DOM based modules )
16405 Roo.each(this.elmodules, function(e) {
16407 if (!this.topModule &&
16408 typeof(e.parent) == 'string' &&
16409 e.parent.substring(0,1) == '#' &&
16410 Roo.get(e.parent.substr(1))
16413 _this.topModule = e;
16419 // add modules to their parents..
16420 var addMod = function(m) {
16421 Roo.debug && Roo.log("build Order: add: " + m.name);
16424 if (m.modules && !m.disabled) {
16425 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16426 m.modules.keySort('ASC', cmp );
16427 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16429 m.modules.each(addMod);
16431 Roo.debug && Roo.log("build Order: no child modules");
16433 // not sure if this is used any more..
16435 m.finalize.name = m.name + " (clean up) ";
16436 mods.push(m.finalize);
16440 if (this.topModule && this.topModule.modules) {
16441 this.topModule.modules.keySort('ASC', cmp );
16442 this.topModule.modules.each(addMod);
16448 * Build the registered modules.
16449 * @param {Object} parent element.
16450 * @param {Function} optional method to call after module has been added.
16454 build : function(opts)
16457 if (typeof(opts) != 'undefined') {
16458 Roo.apply(this,opts);
16462 var mods = this.buildOrder();
16464 //this.allmods = mods;
16465 //Roo.debug && Roo.log(mods);
16467 if (!mods.length) { // should not happen
16468 throw "NO modules!!!";
16472 var msg = "Building Interface...";
16473 // flash it up as modal - so we store the mask!?
16474 if (!this.hideProgress && Roo.MessageBox) {
16475 Roo.MessageBox.show({ title: 'loading' });
16476 Roo.MessageBox.show({
16477 title: "Please wait...",
16486 var total = mods.length;
16489 var progressRun = function() {
16490 if (!mods.length) {
16491 Roo.debug && Roo.log('hide?');
16492 if (!this.hideProgress && Roo.MessageBox) {
16493 Roo.MessageBox.hide();
16495 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16497 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16503 var m = mods.shift();
16506 Roo.debug && Roo.log(m);
16507 // not sure if this is supported any more.. - modules that are are just function
16508 if (typeof(m) == 'function') {
16510 return progressRun.defer(10, _this);
16514 msg = "Building Interface " + (total - mods.length) +
16516 (m.name ? (' - ' + m.name) : '');
16517 Roo.debug && Roo.log(msg);
16518 if (!this.hideProgress && Roo.MessageBox) {
16519 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16523 // is the module disabled?
16524 var disabled = (typeof(m.disabled) == 'function') ?
16525 m.disabled.call(m.module.disabled) : m.disabled;
16529 return progressRun(); // we do not update the display!
16537 // it's 10 on top level, and 1 on others??? why...
16538 return progressRun.defer(10, _this);
16541 progressRun.defer(1, _this);
16555 * wrapper for event.on - aliased later..
16556 * Typically use to register a event handler for register:
16558 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16567 Roo.XComponent.event = new Roo.util.Observable({
16571 * Fires when an Component is registered,
16572 * set the disable property on the Component to stop registration.
16573 * @param {Roo.XComponent} c the component being registerd.
16578 * @event beforebuild
16579 * Fires before each Component is built
16580 * can be used to apply permissions.
16581 * @param {Roo.XComponent} c the component being registerd.
16584 'beforebuild' : true,
16586 * @event buildcomplete
16587 * Fires on the top level element when all elements have been built
16588 * @param {Roo.XComponent} the top level component.
16590 'buildcomplete' : true
16595 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16598 * marked - a markdown parser
16599 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16600 * https://github.com/chjj/marked
16606 * Roo.Markdown - is a very crude wrapper around marked..
16610 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16612 * Note: move the sample code to the bottom of this
16613 * file before uncommenting it.
16618 Roo.Markdown.toHtml = function(text) {
16620 var c = new Roo.Markdown.marked.setOptions({
16621 renderer: new Roo.Markdown.marked.Renderer(),
16632 text = text.replace(/\\\n/g,' ');
16633 return Roo.Markdown.marked(text);
16638 // Wraps all "globals" so that the only thing
16639 // exposed is makeHtml().
16644 * Block-Level Grammar
16649 code: /^( {4}[^\n]+\n*)+/,
16651 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16652 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16654 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16655 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16656 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16657 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16658 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16660 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16664 block.bullet = /(?:[*+-]|\d+\.)/;
16665 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16666 block.item = replace(block.item, 'gm')
16667 (/bull/g, block.bullet)
16670 block.list = replace(block.list)
16671 (/bull/g, block.bullet)
16672 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16673 ('def', '\\n+(?=' + block.def.source + ')')
16676 block.blockquote = replace(block.blockquote)
16680 block._tag = '(?!(?:'
16681 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16682 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16683 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16685 block.html = replace(block.html)
16686 ('comment', /<!--[\s\S]*?-->/)
16687 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16688 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16689 (/tag/g, block._tag)
16692 block.paragraph = replace(block.paragraph)
16694 ('heading', block.heading)
16695 ('lheading', block.lheading)
16696 ('blockquote', block.blockquote)
16697 ('tag', '<' + block._tag)
16702 * Normal Block Grammar
16705 block.normal = merge({}, block);
16708 * GFM Block Grammar
16711 block.gfm = merge({}, block.normal, {
16712 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16714 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16717 block.gfm.paragraph = replace(block.paragraph)
16719 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16720 + block.list.source.replace('\\1', '\\3') + '|')
16724 * GFM + Tables Block Grammar
16727 block.tables = merge({}, block.gfm, {
16728 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16729 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16736 function Lexer(options) {
16738 this.tokens.links = {};
16739 this.options = options || marked.defaults;
16740 this.rules = block.normal;
16742 if (this.options.gfm) {
16743 if (this.options.tables) {
16744 this.rules = block.tables;
16746 this.rules = block.gfm;
16752 * Expose Block Rules
16755 Lexer.rules = block;
16758 * Static Lex Method
16761 Lexer.lex = function(src, options) {
16762 var lexer = new Lexer(options);
16763 return lexer.lex(src);
16770 Lexer.prototype.lex = function(src) {
16772 .replace(/\r\n|\r/g, '\n')
16773 .replace(/\t/g, ' ')
16774 .replace(/\u00a0/g, ' ')
16775 .replace(/\u2424/g, '\n');
16777 return this.token(src, true);
16784 Lexer.prototype.token = function(src, top, bq) {
16785 var src = src.replace(/^ +$/gm, '')
16798 if (cap = this.rules.newline.exec(src)) {
16799 src = src.substring(cap[0].length);
16800 if (cap[0].length > 1) {
16808 if (cap = this.rules.code.exec(src)) {
16809 src = src.substring(cap[0].length);
16810 cap = cap[0].replace(/^ {4}/gm, '');
16813 text: !this.options.pedantic
16814 ? cap.replace(/\n+$/, '')
16821 if (cap = this.rules.fences.exec(src)) {
16822 src = src.substring(cap[0].length);
16832 if (cap = this.rules.heading.exec(src)) {
16833 src = src.substring(cap[0].length);
16836 depth: cap[1].length,
16842 // table no leading pipe (gfm)
16843 if (top && (cap = this.rules.nptable.exec(src))) {
16844 src = src.substring(cap[0].length);
16848 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16849 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16850 cells: cap[3].replace(/\n$/, '').split('\n')
16853 for (i = 0; i < item.align.length; i++) {
16854 if (/^ *-+: *$/.test(item.align[i])) {
16855 item.align[i] = 'right';
16856 } else if (/^ *:-+: *$/.test(item.align[i])) {
16857 item.align[i] = 'center';
16858 } else if (/^ *:-+ *$/.test(item.align[i])) {
16859 item.align[i] = 'left';
16861 item.align[i] = null;
16865 for (i = 0; i < item.cells.length; i++) {
16866 item.cells[i] = item.cells[i].split(/ *\| */);
16869 this.tokens.push(item);
16875 if (cap = this.rules.lheading.exec(src)) {
16876 src = src.substring(cap[0].length);
16879 depth: cap[2] === '=' ? 1 : 2,
16886 if (cap = this.rules.hr.exec(src)) {
16887 src = src.substring(cap[0].length);
16895 if (cap = this.rules.blockquote.exec(src)) {
16896 src = src.substring(cap[0].length);
16899 type: 'blockquote_start'
16902 cap = cap[0].replace(/^ *> ?/gm, '');
16904 // Pass `top` to keep the current
16905 // "toplevel" state. This is exactly
16906 // how markdown.pl works.
16907 this.token(cap, top, true);
16910 type: 'blockquote_end'
16917 if (cap = this.rules.list.exec(src)) {
16918 src = src.substring(cap[0].length);
16922 type: 'list_start',
16923 ordered: bull.length > 1
16926 // Get each top-level item.
16927 cap = cap[0].match(this.rules.item);
16933 for (; i < l; i++) {
16936 // Remove the list item's bullet
16937 // so it is seen as the next token.
16938 space = item.length;
16939 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16941 // Outdent whatever the
16942 // list item contains. Hacky.
16943 if (~item.indexOf('\n ')) {
16944 space -= item.length;
16945 item = !this.options.pedantic
16946 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16947 : item.replace(/^ {1,4}/gm, '');
16950 // Determine whether the next list item belongs here.
16951 // Backpedal if it does not belong in this list.
16952 if (this.options.smartLists && i !== l - 1) {
16953 b = block.bullet.exec(cap[i + 1])[0];
16954 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16955 src = cap.slice(i + 1).join('\n') + src;
16960 // Determine whether item is loose or not.
16961 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16962 // for discount behavior.
16963 loose = next || /\n\n(?!\s*$)/.test(item);
16965 next = item.charAt(item.length - 1) === '\n';
16966 if (!loose) { loose = next; }
16971 ? 'loose_item_start'
16972 : 'list_item_start'
16976 this.token(item, false, bq);
16979 type: 'list_item_end'
16991 if (cap = this.rules.html.exec(src)) {
16992 src = src.substring(cap[0].length);
16994 type: this.options.sanitize
16997 pre: !this.options.sanitizer
16998 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17005 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17006 src = src.substring(cap[0].length);
17007 this.tokens.links[cap[1].toLowerCase()] = {
17015 if (top && (cap = this.rules.table.exec(src))) {
17016 src = src.substring(cap[0].length);
17020 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17021 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17022 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17025 for (i = 0; i < item.align.length; i++) {
17026 if (/^ *-+: *$/.test(item.align[i])) {
17027 item.align[i] = 'right';
17028 } else if (/^ *:-+: *$/.test(item.align[i])) {
17029 item.align[i] = 'center';
17030 } else if (/^ *:-+ *$/.test(item.align[i])) {
17031 item.align[i] = 'left';
17033 item.align[i] = null;
17037 for (i = 0; i < item.cells.length; i++) {
17038 item.cells[i] = item.cells[i]
17039 .replace(/^ *\| *| *\| *$/g, '')
17043 this.tokens.push(item);
17048 // top-level paragraph
17049 if (top && (cap = this.rules.paragraph.exec(src))) {
17050 src = src.substring(cap[0].length);
17053 text: cap[1].charAt(cap[1].length - 1) === '\n'
17054 ? cap[1].slice(0, -1)
17061 if (cap = this.rules.text.exec(src)) {
17062 // Top-level should never reach here.
17063 src = src.substring(cap[0].length);
17073 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17077 return this.tokens;
17081 * Inline-Level Grammar
17085 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17086 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17088 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17089 link: /^!?\[(inside)\]\(href\)/,
17090 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17091 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17092 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17093 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17094 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17095 br: /^ {2,}\n(?!\s*$)/,
17097 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17100 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17101 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17103 inline.link = replace(inline.link)
17104 ('inside', inline._inside)
17105 ('href', inline._href)
17108 inline.reflink = replace(inline.reflink)
17109 ('inside', inline._inside)
17113 * Normal Inline Grammar
17116 inline.normal = merge({}, inline);
17119 * Pedantic Inline Grammar
17122 inline.pedantic = merge({}, inline.normal, {
17123 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17124 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17128 * GFM Inline Grammar
17131 inline.gfm = merge({}, inline.normal, {
17132 escape: replace(inline.escape)('])', '~|])')(),
17133 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17134 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17135 text: replace(inline.text)
17137 ('|', '|https?://|')
17142 * GFM + Line Breaks Inline Grammar
17145 inline.breaks = merge({}, inline.gfm, {
17146 br: replace(inline.br)('{2,}', '*')(),
17147 text: replace(inline.gfm.text)('{2,}', '*')()
17151 * Inline Lexer & Compiler
17154 function InlineLexer(links, options) {
17155 this.options = options || marked.defaults;
17156 this.links = links;
17157 this.rules = inline.normal;
17158 this.renderer = this.options.renderer || new Renderer;
17159 this.renderer.options = this.options;
17163 Error('Tokens array requires a `links` property.');
17166 if (this.options.gfm) {
17167 if (this.options.breaks) {
17168 this.rules = inline.breaks;
17170 this.rules = inline.gfm;
17172 } else if (this.options.pedantic) {
17173 this.rules = inline.pedantic;
17178 * Expose Inline Rules
17181 InlineLexer.rules = inline;
17184 * Static Lexing/Compiling Method
17187 InlineLexer.output = function(src, links, options) {
17188 var inline = new InlineLexer(links, options);
17189 return inline.output(src);
17196 InlineLexer.prototype.output = function(src) {
17205 if (cap = this.rules.escape.exec(src)) {
17206 src = src.substring(cap[0].length);
17212 if (cap = this.rules.autolink.exec(src)) {
17213 src = src.substring(cap[0].length);
17214 if (cap[2] === '@') {
17215 text = cap[1].charAt(6) === ':'
17216 ? this.mangle(cap[1].substring(7))
17217 : this.mangle(cap[1]);
17218 href = this.mangle('mailto:') + text;
17220 text = escape(cap[1]);
17223 out += this.renderer.link(href, null, text);
17228 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17229 src = src.substring(cap[0].length);
17230 text = escape(cap[1]);
17232 out += this.renderer.link(href, null, text);
17237 if (cap = this.rules.tag.exec(src)) {
17238 if (!this.inLink && /^<a /i.test(cap[0])) {
17239 this.inLink = true;
17240 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17241 this.inLink = false;
17243 src = src.substring(cap[0].length);
17244 out += this.options.sanitize
17245 ? this.options.sanitizer
17246 ? this.options.sanitizer(cap[0])
17253 if (cap = this.rules.link.exec(src)) {
17254 src = src.substring(cap[0].length);
17255 this.inLink = true;
17256 out += this.outputLink(cap, {
17260 this.inLink = false;
17265 if ((cap = this.rules.reflink.exec(src))
17266 || (cap = this.rules.nolink.exec(src))) {
17267 src = src.substring(cap[0].length);
17268 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17269 link = this.links[link.toLowerCase()];
17270 if (!link || !link.href) {
17271 out += cap[0].charAt(0);
17272 src = cap[0].substring(1) + src;
17275 this.inLink = true;
17276 out += this.outputLink(cap, link);
17277 this.inLink = false;
17282 if (cap = this.rules.strong.exec(src)) {
17283 src = src.substring(cap[0].length);
17284 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17289 if (cap = this.rules.em.exec(src)) {
17290 src = src.substring(cap[0].length);
17291 out += this.renderer.em(this.output(cap[2] || cap[1]));
17296 if (cap = this.rules.code.exec(src)) {
17297 src = src.substring(cap[0].length);
17298 out += this.renderer.codespan(escape(cap[2], true));
17303 if (cap = this.rules.br.exec(src)) {
17304 src = src.substring(cap[0].length);
17305 out += this.renderer.br();
17310 if (cap = this.rules.del.exec(src)) {
17311 src = src.substring(cap[0].length);
17312 out += this.renderer.del(this.output(cap[1]));
17317 if (cap = this.rules.text.exec(src)) {
17318 src = src.substring(cap[0].length);
17319 out += this.renderer.text(escape(this.smartypants(cap[0])));
17325 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17336 InlineLexer.prototype.outputLink = function(cap, link) {
17337 var href = escape(link.href)
17338 , title = link.title ? escape(link.title) : null;
17340 return cap[0].charAt(0) !== '!'
17341 ? this.renderer.link(href, title, this.output(cap[1]))
17342 : this.renderer.image(href, title, escape(cap[1]));
17346 * Smartypants Transformations
17349 InlineLexer.prototype.smartypants = function(text) {
17350 if (!this.options.smartypants) { return text; }
17353 .replace(/---/g, '\u2014')
17355 .replace(/--/g, '\u2013')
17357 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17358 // closing singles & apostrophes
17359 .replace(/'/g, '\u2019')
17361 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17363 .replace(/"/g, '\u201d')
17365 .replace(/\.{3}/g, '\u2026');
17372 InlineLexer.prototype.mangle = function(text) {
17373 if (!this.options.mangle) { return text; }
17379 for (; i < l; i++) {
17380 ch = text.charCodeAt(i);
17381 if (Math.random() > 0.5) {
17382 ch = 'x' + ch.toString(16);
17384 out += '&#' + ch + ';';
17394 function Renderer(options) {
17395 this.options = options || {};
17398 Renderer.prototype.code = function(code, lang, escaped) {
17399 if (this.options.highlight) {
17400 var out = this.options.highlight(code, lang);
17401 if (out != null && out !== code) {
17406 // hack!!! - it's already escapeD?
17411 return '<pre><code>'
17412 + (escaped ? code : escape(code, true))
17413 + '\n</code></pre>';
17416 return '<pre><code class="'
17417 + this.options.langPrefix
17418 + escape(lang, true)
17420 + (escaped ? code : escape(code, true))
17421 + '\n</code></pre>\n';
17424 Renderer.prototype.blockquote = function(quote) {
17425 return '<blockquote>\n' + quote + '</blockquote>\n';
17428 Renderer.prototype.html = function(html) {
17432 Renderer.prototype.heading = function(text, level, raw) {
17436 + this.options.headerPrefix
17437 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17445 Renderer.prototype.hr = function() {
17446 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17449 Renderer.prototype.list = function(body, ordered) {
17450 var type = ordered ? 'ol' : 'ul';
17451 return '<' + type + '>\n' + body + '</' + type + '>\n';
17454 Renderer.prototype.listitem = function(text) {
17455 return '<li>' + text + '</li>\n';
17458 Renderer.prototype.paragraph = function(text) {
17459 return '<p>' + text + '</p>\n';
17462 Renderer.prototype.table = function(header, body) {
17463 return '<table class="table table-striped">\n'
17473 Renderer.prototype.tablerow = function(content) {
17474 return '<tr>\n' + content + '</tr>\n';
17477 Renderer.prototype.tablecell = function(content, flags) {
17478 var type = flags.header ? 'th' : 'td';
17479 var tag = flags.align
17480 ? '<' + type + ' style="text-align:' + flags.align + '">'
17481 : '<' + type + '>';
17482 return tag + content + '</' + type + '>\n';
17485 // span level renderer
17486 Renderer.prototype.strong = function(text) {
17487 return '<strong>' + text + '</strong>';
17490 Renderer.prototype.em = function(text) {
17491 return '<em>' + text + '</em>';
17494 Renderer.prototype.codespan = function(text) {
17495 return '<code>' + text + '</code>';
17498 Renderer.prototype.br = function() {
17499 return this.options.xhtml ? '<br/>' : '<br>';
17502 Renderer.prototype.del = function(text) {
17503 return '<del>' + text + '</del>';
17506 Renderer.prototype.link = function(href, title, text) {
17507 if (this.options.sanitize) {
17509 var prot = decodeURIComponent(unescape(href))
17510 .replace(/[^\w:]/g, '')
17515 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17519 var out = '<a href="' + href + '"';
17521 out += ' title="' + title + '"';
17523 out += '>' + text + '</a>';
17527 Renderer.prototype.image = function(href, title, text) {
17528 var out = '<img src="' + href + '" alt="' + text + '"';
17530 out += ' title="' + title + '"';
17532 out += this.options.xhtml ? '/>' : '>';
17536 Renderer.prototype.text = function(text) {
17541 * Parsing & Compiling
17544 function Parser(options) {
17547 this.options = options || marked.defaults;
17548 this.options.renderer = this.options.renderer || new Renderer;
17549 this.renderer = this.options.renderer;
17550 this.renderer.options = this.options;
17554 * Static Parse Method
17557 Parser.parse = function(src, options, renderer) {
17558 var parser = new Parser(options, renderer);
17559 return parser.parse(src);
17566 Parser.prototype.parse = function(src) {
17567 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17568 this.tokens = src.reverse();
17571 while (this.next()) {
17582 Parser.prototype.next = function() {
17583 return this.token = this.tokens.pop();
17587 * Preview Next Token
17590 Parser.prototype.peek = function() {
17591 return this.tokens[this.tokens.length - 1] || 0;
17595 * Parse Text Tokens
17598 Parser.prototype.parseText = function() {
17599 var body = this.token.text;
17601 while (this.peek().type === 'text') {
17602 body += '\n' + this.next().text;
17605 return this.inline.output(body);
17609 * Parse Current Token
17612 Parser.prototype.tok = function() {
17613 switch (this.token.type) {
17618 return this.renderer.hr();
17621 return this.renderer.heading(
17622 this.inline.output(this.token.text),
17627 return this.renderer.code(this.token.text,
17629 this.token.escaped);
17642 for (i = 0; i < this.token.header.length; i++) {
17643 flags = { header: true, align: this.token.align[i] };
17644 cell += this.renderer.tablecell(
17645 this.inline.output(this.token.header[i]),
17646 { header: true, align: this.token.align[i] }
17649 header += this.renderer.tablerow(cell);
17651 for (i = 0; i < this.token.cells.length; i++) {
17652 row = this.token.cells[i];
17655 for (j = 0; j < row.length; j++) {
17656 cell += this.renderer.tablecell(
17657 this.inline.output(row[j]),
17658 { header: false, align: this.token.align[j] }
17662 body += this.renderer.tablerow(cell);
17664 return this.renderer.table(header, body);
17666 case 'blockquote_start': {
17669 while (this.next().type !== 'blockquote_end') {
17670 body += this.tok();
17673 return this.renderer.blockquote(body);
17675 case 'list_start': {
17677 , ordered = this.token.ordered;
17679 while (this.next().type !== 'list_end') {
17680 body += this.tok();
17683 return this.renderer.list(body, ordered);
17685 case 'list_item_start': {
17688 while (this.next().type !== 'list_item_end') {
17689 body += this.token.type === 'text'
17694 return this.renderer.listitem(body);
17696 case 'loose_item_start': {
17699 while (this.next().type !== 'list_item_end') {
17700 body += this.tok();
17703 return this.renderer.listitem(body);
17706 var html = !this.token.pre && !this.options.pedantic
17707 ? this.inline.output(this.token.text)
17709 return this.renderer.html(html);
17711 case 'paragraph': {
17712 return this.renderer.paragraph(this.inline.output(this.token.text));
17715 return this.renderer.paragraph(this.parseText());
17724 function escape(html, encode) {
17726 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17727 .replace(/</g, '<')
17728 .replace(/>/g, '>')
17729 .replace(/"/g, '"')
17730 .replace(/'/g, ''');
17733 function unescape(html) {
17734 // explicitly match decimal, hex, and named HTML entities
17735 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17736 n = n.toLowerCase();
17737 if (n === 'colon') { return ':'; }
17738 if (n.charAt(0) === '#') {
17739 return n.charAt(1) === 'x'
17740 ? String.fromCharCode(parseInt(n.substring(2), 16))
17741 : String.fromCharCode(+n.substring(1));
17747 function replace(regex, opt) {
17748 regex = regex.source;
17750 return function self(name, val) {
17751 if (!name) { return new RegExp(regex, opt); }
17752 val = val.source || val;
17753 val = val.replace(/(^|[^\[])\^/g, '$1');
17754 regex = regex.replace(name, val);
17762 function merge(obj) {
17767 for (; i < arguments.length; i++) {
17768 target = arguments[i];
17769 for (key in target) {
17770 if (Object.prototype.hasOwnProperty.call(target, key)) {
17771 obj[key] = target[key];
17784 function marked(src, opt, callback) {
17785 if (callback || typeof opt === 'function') {
17791 opt = merge({}, marked.defaults, opt || {});
17793 var highlight = opt.highlight
17799 tokens = Lexer.lex(src, opt)
17801 return callback(e);
17804 pending = tokens.length;
17806 var done = function(err) {
17808 opt.highlight = highlight;
17809 return callback(err);
17815 out = Parser.parse(tokens, opt);
17820 opt.highlight = highlight;
17824 : callback(null, out);
17827 if (!highlight || highlight.length < 3) {
17831 delete opt.highlight;
17833 if (!pending) { return done(); }
17835 for (; i < tokens.length; i++) {
17837 if (token.type !== 'code') {
17838 return --pending || done();
17840 return highlight(token.text, token.lang, function(err, code) {
17841 if (err) { return done(err); }
17842 if (code == null || code === token.text) {
17843 return --pending || done();
17846 token.escaped = true;
17847 --pending || done();
17855 if (opt) { opt = merge({}, marked.defaults, opt); }
17856 return Parser.parse(Lexer.lex(src, opt), opt);
17858 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17859 if ((opt || marked.defaults).silent) {
17860 return '<p>An error occured:</p><pre>'
17861 + escape(e.message + '', true)
17873 marked.setOptions = function(opt) {
17874 merge(marked.defaults, opt);
17878 marked.defaults = {
17889 langPrefix: 'lang-',
17890 smartypants: false,
17892 renderer: new Renderer,
17900 marked.Parser = Parser;
17901 marked.parser = Parser.parse;
17903 marked.Renderer = Renderer;
17905 marked.Lexer = Lexer;
17906 marked.lexer = Lexer.lex;
17908 marked.InlineLexer = InlineLexer;
17909 marked.inlineLexer = InlineLexer.output;
17911 marked.parse = marked;
17913 Roo.Markdown.marked = marked;
17917 * Ext JS Library 1.1.1
17918 * Copyright(c) 2006-2007, Ext JS, LLC.
17920 * Originally Released Under LGPL - original licence link has changed is not relivant.
17923 * <script type="text/javascript">
17929 * These classes are derivatives of the similarly named classes in the YUI Library.
17930 * The original license:
17931 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17932 * Code licensed under the BSD License:
17933 * http://developer.yahoo.net/yui/license.txt
17938 var Event=Roo.EventManager;
17939 var Dom=Roo.lib.Dom;
17942 * @class Roo.dd.DragDrop
17943 * @extends Roo.util.Observable
17944 * Defines the interface and base operation of items that that can be
17945 * dragged or can be drop targets. It was designed to be extended, overriding
17946 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17947 * Up to three html elements can be associated with a DragDrop instance:
17949 * <li>linked element: the element that is passed into the constructor.
17950 * This is the element which defines the boundaries for interaction with
17951 * other DragDrop objects.</li>
17952 * <li>handle element(s): The drag operation only occurs if the element that
17953 * was clicked matches a handle element. By default this is the linked
17954 * element, but there are times that you will want only a portion of the
17955 * linked element to initiate the drag operation, and the setHandleElId()
17956 * method provides a way to define this.</li>
17957 * <li>drag element: this represents the element that would be moved along
17958 * with the cursor during a drag operation. By default, this is the linked
17959 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17960 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17963 * This class should not be instantiated until the onload event to ensure that
17964 * the associated elements are available.
17965 * The following would define a DragDrop obj that would interact with any
17966 * other DragDrop obj in the "group1" group:
17968 * dd = new Roo.dd.DragDrop("div1", "group1");
17970 * Since none of the event handlers have been implemented, nothing would
17971 * actually happen if you were to run the code above. Normally you would
17972 * override this class or one of the default implementations, but you can
17973 * also override the methods you want on an instance of the class...
17975 * dd.onDragDrop = function(e, id) {
17976 * alert("dd was dropped on " + id);
17980 * @param {String} id of the element that is linked to this instance
17981 * @param {String} sGroup the group of related DragDrop objects
17982 * @param {object} config an object containing configurable attributes
17983 * Valid properties for DragDrop:
17984 * padding, isTarget, maintainOffset, primaryButtonOnly
17986 Roo.dd.DragDrop = function(id, sGroup, config) {
17988 this.init(id, sGroup, config);
17993 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
17996 * The id of the element associated with this object. This is what we
17997 * refer to as the "linked element" because the size and position of
17998 * this element is used to determine when the drag and drop objects have
18006 * Configuration attributes passed into the constructor
18013 * The id of the element that will be dragged. By default this is same
18014 * as the linked element , but could be changed to another element. Ex:
18016 * @property dragElId
18023 * the id of the element that initiates the drag operation. By default
18024 * this is the linked element, but could be changed to be a child of this
18025 * element. This lets us do things like only starting the drag when the
18026 * header element within the linked html element is clicked.
18027 * @property handleElId
18034 * An associative array of HTML tags that will be ignored if clicked.
18035 * @property invalidHandleTypes
18036 * @type {string: string}
18038 invalidHandleTypes: null,
18041 * An associative array of ids for elements that will be ignored if clicked
18042 * @property invalidHandleIds
18043 * @type {string: string}
18045 invalidHandleIds: null,
18048 * An indexted array of css class names for elements that will be ignored
18050 * @property invalidHandleClasses
18053 invalidHandleClasses: null,
18056 * The linked element's absolute X position at the time the drag was
18058 * @property startPageX
18065 * The linked element's absolute X position at the time the drag was
18067 * @property startPageY
18074 * The group defines a logical collection of DragDrop objects that are
18075 * related. Instances only get events when interacting with other
18076 * DragDrop object in the same group. This lets us define multiple
18077 * groups using a single DragDrop subclass if we want.
18079 * @type {string: string}
18084 * Individual drag/drop instances can be locked. This will prevent
18085 * onmousedown start drag.
18093 * Lock this instance
18096 lock: function() { this.locked = true; },
18099 * Unlock this instace
18102 unlock: function() { this.locked = false; },
18105 * By default, all insances can be a drop target. This can be disabled by
18106 * setting isTarget to false.
18113 * The padding configured for this drag and drop object for calculating
18114 * the drop zone intersection with this object.
18121 * Cached reference to the linked element
18122 * @property _domRef
18128 * Internal typeof flag
18129 * @property __ygDragDrop
18132 __ygDragDrop: true,
18135 * Set to true when horizontal contraints are applied
18136 * @property constrainX
18143 * Set to true when vertical contraints are applied
18144 * @property constrainY
18151 * The left constraint
18159 * The right constraint
18167 * The up constraint
18176 * The down constraint
18184 * Maintain offsets when we resetconstraints. Set to true when you want
18185 * the position of the element relative to its parent to stay the same
18186 * when the page changes
18188 * @property maintainOffset
18191 maintainOffset: false,
18194 * Array of pixel locations the element will snap to if we specified a
18195 * horizontal graduation/interval. This array is generated automatically
18196 * when you define a tick interval.
18203 * Array of pixel locations the element will snap to if we specified a
18204 * vertical graduation/interval. This array is generated automatically
18205 * when you define a tick interval.
18212 * By default the drag and drop instance will only respond to the primary
18213 * button click (left button for a right-handed mouse). Set to true to
18214 * allow drag and drop to start with any mouse click that is propogated
18216 * @property primaryButtonOnly
18219 primaryButtonOnly: true,
18222 * The availabe property is false until the linked dom element is accessible.
18223 * @property available
18229 * By default, drags can only be initiated if the mousedown occurs in the
18230 * region the linked element is. This is done in part to work around a
18231 * bug in some browsers that mis-report the mousedown if the previous
18232 * mouseup happened outside of the window. This property is set to true
18233 * if outer handles are defined.
18235 * @property hasOuterHandles
18239 hasOuterHandles: false,
18242 * Code that executes immediately before the startDrag event
18243 * @method b4StartDrag
18246 b4StartDrag: function(x, y) { },
18249 * Abstract method called after a drag/drop object is clicked
18250 * and the drag or mousedown time thresholds have beeen met.
18251 * @method startDrag
18252 * @param {int} X click location
18253 * @param {int} Y click location
18255 startDrag: function(x, y) { /* override this */ },
18258 * Code that executes immediately before the onDrag event
18262 b4Drag: function(e) { },
18265 * Abstract method called during the onMouseMove event while dragging an
18268 * @param {Event} e the mousemove event
18270 onDrag: function(e) { /* override this */ },
18273 * Abstract method called when this element fist begins hovering over
18274 * another DragDrop obj
18275 * @method onDragEnter
18276 * @param {Event} e the mousemove event
18277 * @param {String|DragDrop[]} id In POINT mode, the element
18278 * id this is hovering over. In INTERSECT mode, an array of one or more
18279 * dragdrop items being hovered over.
18281 onDragEnter: function(e, id) { /* override this */ },
18284 * Code that executes immediately before the onDragOver event
18285 * @method b4DragOver
18288 b4DragOver: function(e) { },
18291 * Abstract method called when this element is hovering over another
18293 * @method onDragOver
18294 * @param {Event} e the mousemove event
18295 * @param {String|DragDrop[]} id In POINT mode, the element
18296 * id this is hovering over. In INTERSECT mode, an array of dd items
18297 * being hovered over.
18299 onDragOver: function(e, id) { /* override this */ },
18302 * Code that executes immediately before the onDragOut event
18303 * @method b4DragOut
18306 b4DragOut: function(e) { },
18309 * Abstract method called when we are no longer hovering over an element
18310 * @method onDragOut
18311 * @param {Event} e the mousemove event
18312 * @param {String|DragDrop[]} id In POINT mode, the element
18313 * id this was hovering over. In INTERSECT mode, an array of dd items
18314 * that the mouse is no longer over.
18316 onDragOut: function(e, id) { /* override this */ },
18319 * Code that executes immediately before the onDragDrop event
18320 * @method b4DragDrop
18323 b4DragDrop: function(e) { },
18326 * Abstract method called when this item is dropped on another DragDrop
18328 * @method onDragDrop
18329 * @param {Event} e the mouseup event
18330 * @param {String|DragDrop[]} id In POINT mode, the element
18331 * id this was dropped on. In INTERSECT mode, an array of dd items this
18334 onDragDrop: function(e, id) { /* override this */ },
18337 * Abstract method called when this item is dropped on an area with no
18339 * @method onInvalidDrop
18340 * @param {Event} e the mouseup event
18342 onInvalidDrop: function(e) { /* override this */ },
18345 * Code that executes immediately before the endDrag event
18346 * @method b4EndDrag
18349 b4EndDrag: function(e) { },
18352 * Fired when we are done dragging the object
18354 * @param {Event} e the mouseup event
18356 endDrag: function(e) { /* override this */ },
18359 * Code executed immediately before the onMouseDown event
18360 * @method b4MouseDown
18361 * @param {Event} e the mousedown event
18364 b4MouseDown: function(e) { },
18367 * Event handler that fires when a drag/drop obj gets a mousedown
18368 * @method onMouseDown
18369 * @param {Event} e the mousedown event
18371 onMouseDown: function(e) { /* override this */ },
18374 * Event handler that fires when a drag/drop obj gets a mouseup
18375 * @method onMouseUp
18376 * @param {Event} e the mouseup event
18378 onMouseUp: function(e) { /* override this */ },
18381 * Override the onAvailable method to do what is needed after the initial
18382 * position was determined.
18383 * @method onAvailable
18385 onAvailable: function () {
18389 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18392 defaultPadding : {left:0, right:0, top:0, bottom:0},
18395 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18399 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18400 { dragElId: "existingProxyDiv" });
18401 dd.startDrag = function(){
18402 this.constrainTo("parent-id");
18405 * Or you can initalize it using the {@link Roo.Element} object:
18407 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18408 startDrag : function(){
18409 this.constrainTo("parent-id");
18413 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18414 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18415 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18416 * an object containing the sides to pad. For example: {right:10, bottom:10}
18417 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18419 constrainTo : function(constrainTo, pad, inContent){
18420 if(typeof pad == "number"){
18421 pad = {left: pad, right:pad, top:pad, bottom:pad};
18423 pad = pad || this.defaultPadding;
18424 var b = Roo.get(this.getEl()).getBox();
18425 var ce = Roo.get(constrainTo);
18426 var s = ce.getScroll();
18427 var c, cd = ce.dom;
18428 if(cd == document.body){
18429 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18432 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18436 var topSpace = b.y - c.y;
18437 var leftSpace = b.x - c.x;
18439 this.resetConstraints();
18440 this.setXConstraint(leftSpace - (pad.left||0), // left
18441 c.width - leftSpace - b.width - (pad.right||0) //right
18443 this.setYConstraint(topSpace - (pad.top||0), //top
18444 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18449 * Returns a reference to the linked element
18451 * @return {HTMLElement} the html element
18453 getEl: function() {
18454 if (!this._domRef) {
18455 this._domRef = Roo.getDom(this.id);
18458 return this._domRef;
18462 * Returns a reference to the actual element to drag. By default this is
18463 * the same as the html element, but it can be assigned to another
18464 * element. An example of this can be found in Roo.dd.DDProxy
18465 * @method getDragEl
18466 * @return {HTMLElement} the html element
18468 getDragEl: function() {
18469 return Roo.getDom(this.dragElId);
18473 * Sets up the DragDrop object. Must be called in the constructor of any
18474 * Roo.dd.DragDrop subclass
18476 * @param id the id of the linked element
18477 * @param {String} sGroup the group of related items
18478 * @param {object} config configuration attributes
18480 init: function(id, sGroup, config) {
18481 this.initTarget(id, sGroup, config);
18482 if (!Roo.isTouch) {
18483 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18485 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18486 // Event.on(this.id, "selectstart", Event.preventDefault);
18490 * Initializes Targeting functionality only... the object does not
18491 * get a mousedown handler.
18492 * @method initTarget
18493 * @param id the id of the linked element
18494 * @param {String} sGroup the group of related items
18495 * @param {object} config configuration attributes
18497 initTarget: function(id, sGroup, config) {
18499 // configuration attributes
18500 this.config = config || {};
18502 // create a local reference to the drag and drop manager
18503 this.DDM = Roo.dd.DDM;
18504 // initialize the groups array
18507 // assume that we have an element reference instead of an id if the
18508 // parameter is not a string
18509 if (typeof id !== "string") {
18516 // add to an interaction group
18517 this.addToGroup((sGroup) ? sGroup : "default");
18519 // We don't want to register this as the handle with the manager
18520 // so we just set the id rather than calling the setter.
18521 this.handleElId = id;
18523 // the linked element is the element that gets dragged by default
18524 this.setDragElId(id);
18526 // by default, clicked anchors will not start drag operations.
18527 this.invalidHandleTypes = { A: "A" };
18528 this.invalidHandleIds = {};
18529 this.invalidHandleClasses = [];
18531 this.applyConfig();
18533 this.handleOnAvailable();
18537 * Applies the configuration parameters that were passed into the constructor.
18538 * This is supposed to happen at each level through the inheritance chain. So
18539 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18540 * DragDrop in order to get all of the parameters that are available in
18542 * @method applyConfig
18544 applyConfig: function() {
18546 // configurable properties:
18547 // padding, isTarget, maintainOffset, primaryButtonOnly
18548 this.padding = this.config.padding || [0, 0, 0, 0];
18549 this.isTarget = (this.config.isTarget !== false);
18550 this.maintainOffset = (this.config.maintainOffset);
18551 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18556 * Executed when the linked element is available
18557 * @method handleOnAvailable
18560 handleOnAvailable: function() {
18561 this.available = true;
18562 this.resetConstraints();
18563 this.onAvailable();
18567 * Configures the padding for the target zone in px. Effectively expands
18568 * (or reduces) the virtual object size for targeting calculations.
18569 * Supports css-style shorthand; if only one parameter is passed, all sides
18570 * will have that padding, and if only two are passed, the top and bottom
18571 * will have the first param, the left and right the second.
18572 * @method setPadding
18573 * @param {int} iTop Top pad
18574 * @param {int} iRight Right pad
18575 * @param {int} iBot Bot pad
18576 * @param {int} iLeft Left pad
18578 setPadding: function(iTop, iRight, iBot, iLeft) {
18579 // this.padding = [iLeft, iRight, iTop, iBot];
18580 if (!iRight && 0 !== iRight) {
18581 this.padding = [iTop, iTop, iTop, iTop];
18582 } else if (!iBot && 0 !== iBot) {
18583 this.padding = [iTop, iRight, iTop, iRight];
18585 this.padding = [iTop, iRight, iBot, iLeft];
18590 * Stores the initial placement of the linked element.
18591 * @method setInitialPosition
18592 * @param {int} diffX the X offset, default 0
18593 * @param {int} diffY the Y offset, default 0
18595 setInitPosition: function(diffX, diffY) {
18596 var el = this.getEl();
18598 if (!this.DDM.verifyEl(el)) {
18602 var dx = diffX || 0;
18603 var dy = diffY || 0;
18605 var p = Dom.getXY( el );
18607 this.initPageX = p[0] - dx;
18608 this.initPageY = p[1] - dy;
18610 this.lastPageX = p[0];
18611 this.lastPageY = p[1];
18614 this.setStartPosition(p);
18618 * Sets the start position of the element. This is set when the obj
18619 * is initialized, the reset when a drag is started.
18620 * @method setStartPosition
18621 * @param pos current position (from previous lookup)
18624 setStartPosition: function(pos) {
18625 var p = pos || Dom.getXY( this.getEl() );
18626 this.deltaSetXY = null;
18628 this.startPageX = p[0];
18629 this.startPageY = p[1];
18633 * Add this instance to a group of related drag/drop objects. All
18634 * instances belong to at least one group, and can belong to as many
18635 * groups as needed.
18636 * @method addToGroup
18637 * @param sGroup {string} the name of the group
18639 addToGroup: function(sGroup) {
18640 this.groups[sGroup] = true;
18641 this.DDM.regDragDrop(this, sGroup);
18645 * Remove's this instance from the supplied interaction group
18646 * @method removeFromGroup
18647 * @param {string} sGroup The group to drop
18649 removeFromGroup: function(sGroup) {
18650 if (this.groups[sGroup]) {
18651 delete this.groups[sGroup];
18654 this.DDM.removeDDFromGroup(this, sGroup);
18658 * Allows you to specify that an element other than the linked element
18659 * will be moved with the cursor during a drag
18660 * @method setDragElId
18661 * @param id {string} the id of the element that will be used to initiate the drag
18663 setDragElId: function(id) {
18664 this.dragElId = id;
18668 * Allows you to specify a child of the linked element that should be
18669 * used to initiate the drag operation. An example of this would be if
18670 * you have a content div with text and links. Clicking anywhere in the
18671 * content area would normally start the drag operation. Use this method
18672 * to specify that an element inside of the content div is the element
18673 * that starts the drag operation.
18674 * @method setHandleElId
18675 * @param id {string} the id of the element that will be used to
18676 * initiate the drag.
18678 setHandleElId: function(id) {
18679 if (typeof id !== "string") {
18682 this.handleElId = id;
18683 this.DDM.regHandle(this.id, id);
18687 * Allows you to set an element outside of the linked element as a drag
18689 * @method setOuterHandleElId
18690 * @param id the id of the element that will be used to initiate the drag
18692 setOuterHandleElId: function(id) {
18693 if (typeof id !== "string") {
18696 Event.on(id, "mousedown",
18697 this.handleMouseDown, this);
18698 this.setHandleElId(id);
18700 this.hasOuterHandles = true;
18704 * Remove all drag and drop hooks for this element
18707 unreg: function() {
18708 Event.un(this.id, "mousedown",
18709 this.handleMouseDown);
18710 Event.un(this.id, "touchstart",
18711 this.handleMouseDown);
18712 this._domRef = null;
18713 this.DDM._remove(this);
18716 destroy : function(){
18721 * Returns true if this instance is locked, or the drag drop mgr is locked
18722 * (meaning that all drag/drop is disabled on the page.)
18724 * @return {boolean} true if this obj or all drag/drop is locked, else
18727 isLocked: function() {
18728 return (this.DDM.isLocked() || this.locked);
18732 * Fired when this object is clicked
18733 * @method handleMouseDown
18735 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18738 handleMouseDown: function(e, oDD){
18740 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18741 //Roo.log('not touch/ button !=0');
18744 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18745 return; // double touch..
18749 if (this.isLocked()) {
18750 //Roo.log('locked');
18754 this.DDM.refreshCache(this.groups);
18755 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18756 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18757 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18758 //Roo.log('no outer handes or not over target');
18761 // Roo.log('check validator');
18762 if (this.clickValidator(e)) {
18763 // Roo.log('validate success');
18764 // set the initial element position
18765 this.setStartPosition();
18768 this.b4MouseDown(e);
18769 this.onMouseDown(e);
18771 this.DDM.handleMouseDown(e, this);
18773 this.DDM.stopEvent(e);
18781 clickValidator: function(e) {
18782 var target = e.getTarget();
18783 return ( this.isValidHandleChild(target) &&
18784 (this.id == this.handleElId ||
18785 this.DDM.handleWasClicked(target, this.id)) );
18789 * Allows you to specify a tag name that should not start a drag operation
18790 * when clicked. This is designed to facilitate embedding links within a
18791 * drag handle that do something other than start the drag.
18792 * @method addInvalidHandleType
18793 * @param {string} tagName the type of element to exclude
18795 addInvalidHandleType: function(tagName) {
18796 var type = tagName.toUpperCase();
18797 this.invalidHandleTypes[type] = type;
18801 * Lets you to specify an element id for a child of a drag handle
18802 * that should not initiate a drag
18803 * @method addInvalidHandleId
18804 * @param {string} id the element id of the element you wish to ignore
18806 addInvalidHandleId: function(id) {
18807 if (typeof id !== "string") {
18810 this.invalidHandleIds[id] = id;
18814 * Lets you specify a css class of elements that will not initiate a drag
18815 * @method addInvalidHandleClass
18816 * @param {string} cssClass the class of the elements you wish to ignore
18818 addInvalidHandleClass: function(cssClass) {
18819 this.invalidHandleClasses.push(cssClass);
18823 * Unsets an excluded tag name set by addInvalidHandleType
18824 * @method removeInvalidHandleType
18825 * @param {string} tagName the type of element to unexclude
18827 removeInvalidHandleType: function(tagName) {
18828 var type = tagName.toUpperCase();
18829 // this.invalidHandleTypes[type] = null;
18830 delete this.invalidHandleTypes[type];
18834 * Unsets an invalid handle id
18835 * @method removeInvalidHandleId
18836 * @param {string} id the id of the element to re-enable
18838 removeInvalidHandleId: function(id) {
18839 if (typeof id !== "string") {
18842 delete this.invalidHandleIds[id];
18846 * Unsets an invalid css class
18847 * @method removeInvalidHandleClass
18848 * @param {string} cssClass the class of the element(s) you wish to
18851 removeInvalidHandleClass: function(cssClass) {
18852 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18853 if (this.invalidHandleClasses[i] == cssClass) {
18854 delete this.invalidHandleClasses[i];
18860 * Checks the tag exclusion list to see if this click should be ignored
18861 * @method isValidHandleChild
18862 * @param {HTMLElement} node the HTMLElement to evaluate
18863 * @return {boolean} true if this is a valid tag type, false if not
18865 isValidHandleChild: function(node) {
18868 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18871 nodeName = node.nodeName.toUpperCase();
18873 nodeName = node.nodeName;
18875 valid = valid && !this.invalidHandleTypes[nodeName];
18876 valid = valid && !this.invalidHandleIds[node.id];
18878 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18879 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18888 * Create the array of horizontal tick marks if an interval was specified
18889 * in setXConstraint().
18890 * @method setXTicks
18893 setXTicks: function(iStartX, iTickSize) {
18895 this.xTickSize = iTickSize;
18899 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18901 this.xTicks[this.xTicks.length] = i;
18906 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18908 this.xTicks[this.xTicks.length] = i;
18913 this.xTicks.sort(this.DDM.numericSort) ;
18917 * Create the array of vertical tick marks if an interval was specified in
18918 * setYConstraint().
18919 * @method setYTicks
18922 setYTicks: function(iStartY, iTickSize) {
18924 this.yTickSize = iTickSize;
18928 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18930 this.yTicks[this.yTicks.length] = i;
18935 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18937 this.yTicks[this.yTicks.length] = i;
18942 this.yTicks.sort(this.DDM.numericSort) ;
18946 * By default, the element can be dragged any place on the screen. Use
18947 * this method to limit the horizontal travel of the element. Pass in
18948 * 0,0 for the parameters if you want to lock the drag to the y axis.
18949 * @method setXConstraint
18950 * @param {int} iLeft the number of pixels the element can move to the left
18951 * @param {int} iRight the number of pixels the element can move to the
18953 * @param {int} iTickSize optional parameter for specifying that the
18955 * should move iTickSize pixels at a time.
18957 setXConstraint: function(iLeft, iRight, iTickSize) {
18958 this.leftConstraint = iLeft;
18959 this.rightConstraint = iRight;
18961 this.minX = this.initPageX - iLeft;
18962 this.maxX = this.initPageX + iRight;
18963 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18965 this.constrainX = true;
18969 * Clears any constraints applied to this instance. Also clears ticks
18970 * since they can't exist independent of a constraint at this time.
18971 * @method clearConstraints
18973 clearConstraints: function() {
18974 this.constrainX = false;
18975 this.constrainY = false;
18980 * Clears any tick interval defined for this instance
18981 * @method clearTicks
18983 clearTicks: function() {
18984 this.xTicks = null;
18985 this.yTicks = null;
18986 this.xTickSize = 0;
18987 this.yTickSize = 0;
18991 * By default, the element can be dragged any place on the screen. Set
18992 * this to limit the vertical travel of the element. Pass in 0,0 for the
18993 * parameters if you want to lock the drag to the x axis.
18994 * @method setYConstraint
18995 * @param {int} iUp the number of pixels the element can move up
18996 * @param {int} iDown the number of pixels the element can move down
18997 * @param {int} iTickSize optional parameter for specifying that the
18998 * element should move iTickSize pixels at a time.
19000 setYConstraint: function(iUp, iDown, iTickSize) {
19001 this.topConstraint = iUp;
19002 this.bottomConstraint = iDown;
19004 this.minY = this.initPageY - iUp;
19005 this.maxY = this.initPageY + iDown;
19006 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19008 this.constrainY = true;
19013 * resetConstraints must be called if you manually reposition a dd element.
19014 * @method resetConstraints
19015 * @param {boolean} maintainOffset
19017 resetConstraints: function() {
19020 // Maintain offsets if necessary
19021 if (this.initPageX || this.initPageX === 0) {
19022 // figure out how much this thing has moved
19023 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19024 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19026 this.setInitPosition(dx, dy);
19028 // This is the first time we have detected the element's position
19030 this.setInitPosition();
19033 if (this.constrainX) {
19034 this.setXConstraint( this.leftConstraint,
19035 this.rightConstraint,
19039 if (this.constrainY) {
19040 this.setYConstraint( this.topConstraint,
19041 this.bottomConstraint,
19047 * Normally the drag element is moved pixel by pixel, but we can specify
19048 * that it move a number of pixels at a time. This method resolves the
19049 * location when we have it set up like this.
19051 * @param {int} val where we want to place the object
19052 * @param {int[]} tickArray sorted array of valid points
19053 * @return {int} the closest tick
19056 getTick: function(val, tickArray) {
19059 // If tick interval is not defined, it is effectively 1 pixel,
19060 // so we return the value passed to us.
19062 } else if (tickArray[0] >= val) {
19063 // The value is lower than the first tick, so we return the first
19065 return tickArray[0];
19067 for (var i=0, len=tickArray.length; i<len; ++i) {
19069 if (tickArray[next] && tickArray[next] >= val) {
19070 var diff1 = val - tickArray[i];
19071 var diff2 = tickArray[next] - val;
19072 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19076 // The value is larger than the last tick, so we return the last
19078 return tickArray[tickArray.length - 1];
19085 * @return {string} string representation of the dd obj
19087 toString: function() {
19088 return ("DragDrop " + this.id);
19096 * Ext JS Library 1.1.1
19097 * Copyright(c) 2006-2007, Ext JS, LLC.
19099 * Originally Released Under LGPL - original licence link has changed is not relivant.
19102 * <script type="text/javascript">
19107 * The drag and drop utility provides a framework for building drag and drop
19108 * applications. In addition to enabling drag and drop for specific elements,
19109 * the drag and drop elements are tracked by the manager class, and the
19110 * interactions between the various elements are tracked during the drag and
19111 * the implementing code is notified about these important moments.
19114 // Only load the library once. Rewriting the manager class would orphan
19115 // existing drag and drop instances.
19116 if (!Roo.dd.DragDropMgr) {
19119 * @class Roo.dd.DragDropMgr
19120 * DragDropMgr is a singleton that tracks the element interaction for
19121 * all DragDrop items in the window. Generally, you will not call
19122 * this class directly, but it does have helper methods that could
19123 * be useful in your DragDrop implementations.
19126 Roo.dd.DragDropMgr = function() {
19128 var Event = Roo.EventManager;
19133 * Two dimensional Array of registered DragDrop objects. The first
19134 * dimension is the DragDrop item group, the second the DragDrop
19137 * @type {string: string}
19144 * Array of element ids defined as drag handles. Used to determine
19145 * if the element that generated the mousedown event is actually the
19146 * handle and not the html element itself.
19147 * @property handleIds
19148 * @type {string: string}
19155 * the DragDrop object that is currently being dragged
19156 * @property dragCurrent
19164 * the DragDrop object(s) that are being hovered over
19165 * @property dragOvers
19173 * the X distance between the cursor and the object being dragged
19182 * the Y distance between the cursor and the object being dragged
19191 * Flag to determine if we should prevent the default behavior of the
19192 * events we define. By default this is true, but this can be set to
19193 * false if you need the default behavior (not recommended)
19194 * @property preventDefault
19198 preventDefault: true,
19201 * Flag to determine if we should stop the propagation of the events
19202 * we generate. This is true by default but you may want to set it to
19203 * false if the html element contains other features that require the
19205 * @property stopPropagation
19209 stopPropagation: true,
19212 * Internal flag that is set to true when drag and drop has been
19214 * @property initialized
19221 * All drag and drop can be disabled.
19229 * Called the first time an element is registered.
19235 this.initialized = true;
19239 * In point mode, drag and drop interaction is defined by the
19240 * location of the cursor during the drag/drop
19248 * In intersect mode, drag and drop interactio nis defined by the
19249 * overlap of two or more drag and drop objects.
19250 * @property INTERSECT
19257 * The current drag and drop mode. Default: POINT
19265 * Runs method on all drag and drop objects
19266 * @method _execOnAll
19270 _execOnAll: function(sMethod, args) {
19271 for (var i in this.ids) {
19272 for (var j in this.ids[i]) {
19273 var oDD = this.ids[i][j];
19274 if (! this.isTypeOfDD(oDD)) {
19277 oDD[sMethod].apply(oDD, args);
19283 * Drag and drop initialization. Sets up the global event handlers
19288 _onLoad: function() {
19292 if (!Roo.isTouch) {
19293 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19294 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19296 Event.on(document, "touchend", this.handleMouseUp, this, true);
19297 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19299 Event.on(window, "unload", this._onUnload, this, true);
19300 Event.on(window, "resize", this._onResize, this, true);
19301 // Event.on(window, "mouseout", this._test);
19306 * Reset constraints on all drag and drop objs
19307 * @method _onResize
19311 _onResize: function(e) {
19312 this._execOnAll("resetConstraints", []);
19316 * Lock all drag and drop functionality
19320 lock: function() { this.locked = true; },
19323 * Unlock all drag and drop functionality
19327 unlock: function() { this.locked = false; },
19330 * Is drag and drop locked?
19332 * @return {boolean} True if drag and drop is locked, false otherwise.
19335 isLocked: function() { return this.locked; },
19338 * Location cache that is set for all drag drop objects when a drag is
19339 * initiated, cleared when the drag is finished.
19340 * @property locationCache
19347 * Set useCache to false if you want to force object the lookup of each
19348 * drag and drop linked element constantly during a drag.
19349 * @property useCache
19356 * The number of pixels that the mouse needs to move after the
19357 * mousedown before the drag is initiated. Default=3;
19358 * @property clickPixelThresh
19362 clickPixelThresh: 3,
19365 * The number of milliseconds after the mousedown event to initiate the
19366 * drag if we don't get a mouseup event. Default=1000
19367 * @property clickTimeThresh
19371 clickTimeThresh: 350,
19374 * Flag that indicates that either the drag pixel threshold or the
19375 * mousdown time threshold has been met
19376 * @property dragThreshMet
19381 dragThreshMet: false,
19384 * Timeout used for the click time threshold
19385 * @property clickTimeout
19390 clickTimeout: null,
19393 * The X position of the mousedown event stored for later use when a
19394 * drag threshold is met.
19403 * The Y position of the mousedown event stored for later use when a
19404 * drag threshold is met.
19413 * Each DragDrop instance must be registered with the DragDropMgr.
19414 * This is executed in DragDrop.init()
19415 * @method regDragDrop
19416 * @param {DragDrop} oDD the DragDrop object to register
19417 * @param {String} sGroup the name of the group this element belongs to
19420 regDragDrop: function(oDD, sGroup) {
19421 if (!this.initialized) { this.init(); }
19423 if (!this.ids[sGroup]) {
19424 this.ids[sGroup] = {};
19426 this.ids[sGroup][oDD.id] = oDD;
19430 * Removes the supplied dd instance from the supplied group. Executed
19431 * by DragDrop.removeFromGroup, so don't call this function directly.
19432 * @method removeDDFromGroup
19436 removeDDFromGroup: function(oDD, sGroup) {
19437 if (!this.ids[sGroup]) {
19438 this.ids[sGroup] = {};
19441 var obj = this.ids[sGroup];
19442 if (obj && obj[oDD.id]) {
19443 delete obj[oDD.id];
19448 * Unregisters a drag and drop item. This is executed in
19449 * DragDrop.unreg, use that method instead of calling this directly.
19454 _remove: function(oDD) {
19455 for (var g in oDD.groups) {
19456 if (g && this.ids[g][oDD.id]) {
19457 delete this.ids[g][oDD.id];
19460 delete this.handleIds[oDD.id];
19464 * Each DragDrop handle element must be registered. This is done
19465 * automatically when executing DragDrop.setHandleElId()
19466 * @method regHandle
19467 * @param {String} sDDId the DragDrop id this element is a handle for
19468 * @param {String} sHandleId the id of the element that is the drag
19472 regHandle: function(sDDId, sHandleId) {
19473 if (!this.handleIds[sDDId]) {
19474 this.handleIds[sDDId] = {};
19476 this.handleIds[sDDId][sHandleId] = sHandleId;
19480 * Utility function to determine if a given element has been
19481 * registered as a drag drop item.
19482 * @method isDragDrop
19483 * @param {String} id the element id to check
19484 * @return {boolean} true if this element is a DragDrop item,
19488 isDragDrop: function(id) {
19489 return ( this.getDDById(id) ) ? true : false;
19493 * Returns the drag and drop instances that are in all groups the
19494 * passed in instance belongs to.
19495 * @method getRelated
19496 * @param {DragDrop} p_oDD the obj to get related data for
19497 * @param {boolean} bTargetsOnly if true, only return targetable objs
19498 * @return {DragDrop[]} the related instances
19501 getRelated: function(p_oDD, bTargetsOnly) {
19503 for (var i in p_oDD.groups) {
19504 for (j in this.ids[i]) {
19505 var dd = this.ids[i][j];
19506 if (! this.isTypeOfDD(dd)) {
19509 if (!bTargetsOnly || dd.isTarget) {
19510 oDDs[oDDs.length] = dd;
19519 * Returns true if the specified dd target is a legal target for
19520 * the specifice drag obj
19521 * @method isLegalTarget
19522 * @param {DragDrop} the drag obj
19523 * @param {DragDrop} the target
19524 * @return {boolean} true if the target is a legal target for the
19528 isLegalTarget: function (oDD, oTargetDD) {
19529 var targets = this.getRelated(oDD, true);
19530 for (var i=0, len=targets.length;i<len;++i) {
19531 if (targets[i].id == oTargetDD.id) {
19540 * My goal is to be able to transparently determine if an object is
19541 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19542 * returns "object", oDD.constructor.toString() always returns
19543 * "DragDrop" and not the name of the subclass. So for now it just
19544 * evaluates a well-known variable in DragDrop.
19545 * @method isTypeOfDD
19546 * @param {Object} the object to evaluate
19547 * @return {boolean} true if typeof oDD = DragDrop
19550 isTypeOfDD: function (oDD) {
19551 return (oDD && oDD.__ygDragDrop);
19555 * Utility function to determine if a given element has been
19556 * registered as a drag drop handle for the given Drag Drop object.
19558 * @param {String} id the element id to check
19559 * @return {boolean} true if this element is a DragDrop handle, false
19563 isHandle: function(sDDId, sHandleId) {
19564 return ( this.handleIds[sDDId] &&
19565 this.handleIds[sDDId][sHandleId] );
19569 * Returns the DragDrop instance for a given id
19570 * @method getDDById
19571 * @param {String} id the id of the DragDrop object
19572 * @return {DragDrop} the drag drop object, null if it is not found
19575 getDDById: function(id) {
19576 for (var i in this.ids) {
19577 if (this.ids[i][id]) {
19578 return this.ids[i][id];
19585 * Fired after a registered DragDrop object gets the mousedown event.
19586 * Sets up the events required to track the object being dragged
19587 * @method handleMouseDown
19588 * @param {Event} e the event
19589 * @param oDD the DragDrop object being dragged
19593 handleMouseDown: function(e, oDD) {
19595 Roo.QuickTips.disable();
19597 this.currentTarget = e.getTarget();
19599 this.dragCurrent = oDD;
19601 var el = oDD.getEl();
19603 // track start position
19604 this.startX = e.getPageX();
19605 this.startY = e.getPageY();
19607 this.deltaX = this.startX - el.offsetLeft;
19608 this.deltaY = this.startY - el.offsetTop;
19610 this.dragThreshMet = false;
19612 this.clickTimeout = setTimeout(
19614 var DDM = Roo.dd.DDM;
19615 DDM.startDrag(DDM.startX, DDM.startY);
19617 this.clickTimeThresh );
19621 * Fired when either the drag pixel threshol or the mousedown hold
19622 * time threshold has been met.
19623 * @method startDrag
19624 * @param x {int} the X position of the original mousedown
19625 * @param y {int} the Y position of the original mousedown
19628 startDrag: function(x, y) {
19629 clearTimeout(this.clickTimeout);
19630 if (this.dragCurrent) {
19631 this.dragCurrent.b4StartDrag(x, y);
19632 this.dragCurrent.startDrag(x, y);
19634 this.dragThreshMet = true;
19638 * Internal function to handle the mouseup event. Will be invoked
19639 * from the context of the document.
19640 * @method handleMouseUp
19641 * @param {Event} e the event
19645 handleMouseUp: function(e) {
19648 Roo.QuickTips.enable();
19650 if (! this.dragCurrent) {
19654 clearTimeout(this.clickTimeout);
19656 if (this.dragThreshMet) {
19657 this.fireEvents(e, true);
19667 * Utility to stop event propagation and event default, if these
19668 * features are turned on.
19669 * @method stopEvent
19670 * @param {Event} e the event as returned by this.getEvent()
19673 stopEvent: function(e){
19674 if(this.stopPropagation) {
19675 e.stopPropagation();
19678 if (this.preventDefault) {
19679 e.preventDefault();
19684 * Internal function to clean up event handlers after the drag
19685 * operation is complete
19687 * @param {Event} e the event
19691 stopDrag: function(e) {
19692 // Fire the drag end event for the item that was dragged
19693 if (this.dragCurrent) {
19694 if (this.dragThreshMet) {
19695 this.dragCurrent.b4EndDrag(e);
19696 this.dragCurrent.endDrag(e);
19699 this.dragCurrent.onMouseUp(e);
19702 this.dragCurrent = null;
19703 this.dragOvers = {};
19707 * Internal function to handle the mousemove event. Will be invoked
19708 * from the context of the html element.
19710 * @TODO figure out what we can do about mouse events lost when the
19711 * user drags objects beyond the window boundary. Currently we can
19712 * detect this in internet explorer by verifying that the mouse is
19713 * down during the mousemove event. Firefox doesn't give us the
19714 * button state on the mousemove event.
19715 * @method handleMouseMove
19716 * @param {Event} e the event
19720 handleMouseMove: function(e) {
19721 if (! this.dragCurrent) {
19725 // var button = e.which || e.button;
19727 // check for IE mouseup outside of page boundary
19728 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19730 return this.handleMouseUp(e);
19733 if (!this.dragThreshMet) {
19734 var diffX = Math.abs(this.startX - e.getPageX());
19735 var diffY = Math.abs(this.startY - e.getPageY());
19736 if (diffX > this.clickPixelThresh ||
19737 diffY > this.clickPixelThresh) {
19738 this.startDrag(this.startX, this.startY);
19742 if (this.dragThreshMet) {
19743 this.dragCurrent.b4Drag(e);
19744 this.dragCurrent.onDrag(e);
19745 if(!this.dragCurrent.moveOnly){
19746 this.fireEvents(e, false);
19756 * Iterates over all of the DragDrop elements to find ones we are
19757 * hovering over or dropping on
19758 * @method fireEvents
19759 * @param {Event} e the event
19760 * @param {boolean} isDrop is this a drop op or a mouseover op?
19764 fireEvents: function(e, isDrop) {
19765 var dc = this.dragCurrent;
19767 // If the user did the mouse up outside of the window, we could
19768 // get here even though we have ended the drag.
19769 if (!dc || dc.isLocked()) {
19773 var pt = e.getPoint();
19775 // cache the previous dragOver array
19781 var enterEvts = [];
19783 // Check to see if the object(s) we were hovering over is no longer
19784 // being hovered over so we can fire the onDragOut event
19785 for (var i in this.dragOvers) {
19787 var ddo = this.dragOvers[i];
19789 if (! this.isTypeOfDD(ddo)) {
19793 if (! this.isOverTarget(pt, ddo, this.mode)) {
19794 outEvts.push( ddo );
19797 oldOvers[i] = true;
19798 delete this.dragOvers[i];
19801 for (var sGroup in dc.groups) {
19803 if ("string" != typeof sGroup) {
19807 for (i in this.ids[sGroup]) {
19808 var oDD = this.ids[sGroup][i];
19809 if (! this.isTypeOfDD(oDD)) {
19813 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19814 if (this.isOverTarget(pt, oDD, this.mode)) {
19815 // look for drop interactions
19817 dropEvts.push( oDD );
19818 // look for drag enter and drag over interactions
19821 // initial drag over: dragEnter fires
19822 if (!oldOvers[oDD.id]) {
19823 enterEvts.push( oDD );
19824 // subsequent drag overs: dragOver fires
19826 overEvts.push( oDD );
19829 this.dragOvers[oDD.id] = oDD;
19837 if (outEvts.length) {
19838 dc.b4DragOut(e, outEvts);
19839 dc.onDragOut(e, outEvts);
19842 if (enterEvts.length) {
19843 dc.onDragEnter(e, enterEvts);
19846 if (overEvts.length) {
19847 dc.b4DragOver(e, overEvts);
19848 dc.onDragOver(e, overEvts);
19851 if (dropEvts.length) {
19852 dc.b4DragDrop(e, dropEvts);
19853 dc.onDragDrop(e, dropEvts);
19857 // fire dragout events
19859 for (i=0, len=outEvts.length; i<len; ++i) {
19860 dc.b4DragOut(e, outEvts[i].id);
19861 dc.onDragOut(e, outEvts[i].id);
19864 // fire enter events
19865 for (i=0,len=enterEvts.length; i<len; ++i) {
19866 // dc.b4DragEnter(e, oDD.id);
19867 dc.onDragEnter(e, enterEvts[i].id);
19870 // fire over events
19871 for (i=0,len=overEvts.length; i<len; ++i) {
19872 dc.b4DragOver(e, overEvts[i].id);
19873 dc.onDragOver(e, overEvts[i].id);
19876 // fire drop events
19877 for (i=0, len=dropEvts.length; i<len; ++i) {
19878 dc.b4DragDrop(e, dropEvts[i].id);
19879 dc.onDragDrop(e, dropEvts[i].id);
19884 // notify about a drop that did not find a target
19885 if (isDrop && !dropEvts.length) {
19886 dc.onInvalidDrop(e);
19892 * Helper function for getting the best match from the list of drag
19893 * and drop objects returned by the drag and drop events when we are
19894 * in INTERSECT mode. It returns either the first object that the
19895 * cursor is over, or the object that has the greatest overlap with
19896 * the dragged element.
19897 * @method getBestMatch
19898 * @param {DragDrop[]} dds The array of drag and drop objects
19900 * @return {DragDrop} The best single match
19903 getBestMatch: function(dds) {
19905 // Return null if the input is not what we expect
19906 //if (!dds || !dds.length || dds.length == 0) {
19908 // If there is only one item, it wins
19909 //} else if (dds.length == 1) {
19911 var len = dds.length;
19916 // Loop through the targeted items
19917 for (var i=0; i<len; ++i) {
19919 // If the cursor is over the object, it wins. If the
19920 // cursor is over multiple matches, the first one we come
19922 if (dd.cursorIsOver) {
19925 // Otherwise the object with the most overlap wins
19928 winner.overlap.getArea() < dd.overlap.getArea()) {
19939 * Refreshes the cache of the top-left and bottom-right points of the
19940 * drag and drop objects in the specified group(s). This is in the
19941 * format that is stored in the drag and drop instance, so typical
19944 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19948 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19950 * @TODO this really should be an indexed array. Alternatively this
19951 * method could accept both.
19952 * @method refreshCache
19953 * @param {Object} groups an associative array of groups to refresh
19956 refreshCache: function(groups) {
19957 for (var sGroup in groups) {
19958 if ("string" != typeof sGroup) {
19961 for (var i in this.ids[sGroup]) {
19962 var oDD = this.ids[sGroup][i];
19964 if (this.isTypeOfDD(oDD)) {
19965 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19966 var loc = this.getLocation(oDD);
19968 this.locationCache[oDD.id] = loc;
19970 delete this.locationCache[oDD.id];
19971 // this will unregister the drag and drop object if
19972 // the element is not in a usable state
19981 * This checks to make sure an element exists and is in the DOM. The
19982 * main purpose is to handle cases where innerHTML is used to remove
19983 * drag and drop objects from the DOM. IE provides an 'unspecified
19984 * error' when trying to access the offsetParent of such an element
19986 * @param {HTMLElement} el the element to check
19987 * @return {boolean} true if the element looks usable
19990 verifyEl: function(el) {
19995 parent = el.offsetParent;
19998 parent = el.offsetParent;
20009 * Returns a Region object containing the drag and drop element's position
20010 * and size, including the padding configured for it
20011 * @method getLocation
20012 * @param {DragDrop} oDD the drag and drop object to get the
20014 * @return {Roo.lib.Region} a Region object representing the total area
20015 * the element occupies, including any padding
20016 * the instance is configured for.
20019 getLocation: function(oDD) {
20020 if (! this.isTypeOfDD(oDD)) {
20024 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20027 pos= Roo.lib.Dom.getXY(el);
20035 x2 = x1 + el.offsetWidth;
20037 y2 = y1 + el.offsetHeight;
20039 t = y1 - oDD.padding[0];
20040 r = x2 + oDD.padding[1];
20041 b = y2 + oDD.padding[2];
20042 l = x1 - oDD.padding[3];
20044 return new Roo.lib.Region( t, r, b, l );
20048 * Checks the cursor location to see if it over the target
20049 * @method isOverTarget
20050 * @param {Roo.lib.Point} pt The point to evaluate
20051 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20052 * @return {boolean} true if the mouse is over the target
20056 isOverTarget: function(pt, oTarget, intersect) {
20057 // use cache if available
20058 var loc = this.locationCache[oTarget.id];
20059 if (!loc || !this.useCache) {
20060 loc = this.getLocation(oTarget);
20061 this.locationCache[oTarget.id] = loc;
20069 oTarget.cursorIsOver = loc.contains( pt );
20071 // DragDrop is using this as a sanity check for the initial mousedown
20072 // in this case we are done. In POINT mode, if the drag obj has no
20073 // contraints, we are also done. Otherwise we need to evaluate the
20074 // location of the target as related to the actual location of the
20075 // dragged element.
20076 var dc = this.dragCurrent;
20077 if (!dc || !dc.getTargetCoord ||
20078 (!intersect && !dc.constrainX && !dc.constrainY)) {
20079 return oTarget.cursorIsOver;
20082 oTarget.overlap = null;
20084 // Get the current location of the drag element, this is the
20085 // location of the mouse event less the delta that represents
20086 // where the original mousedown happened on the element. We
20087 // need to consider constraints and ticks as well.
20088 var pos = dc.getTargetCoord(pt.x, pt.y);
20090 var el = dc.getDragEl();
20091 var curRegion = new Roo.lib.Region( pos.y,
20092 pos.x + el.offsetWidth,
20093 pos.y + el.offsetHeight,
20096 var overlap = curRegion.intersect(loc);
20099 oTarget.overlap = overlap;
20100 return (intersect) ? true : oTarget.cursorIsOver;
20107 * unload event handler
20108 * @method _onUnload
20112 _onUnload: function(e, me) {
20113 Roo.dd.DragDropMgr.unregAll();
20117 * Cleans up the drag and drop events and objects.
20122 unregAll: function() {
20124 if (this.dragCurrent) {
20126 this.dragCurrent = null;
20129 this._execOnAll("unreg", []);
20131 for (i in this.elementCache) {
20132 delete this.elementCache[i];
20135 this.elementCache = {};
20140 * A cache of DOM elements
20141 * @property elementCache
20148 * Get the wrapper for the DOM element specified
20149 * @method getElWrapper
20150 * @param {String} id the id of the element to get
20151 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20153 * @deprecated This wrapper isn't that useful
20156 getElWrapper: function(id) {
20157 var oWrapper = this.elementCache[id];
20158 if (!oWrapper || !oWrapper.el) {
20159 oWrapper = this.elementCache[id] =
20160 new this.ElementWrapper(Roo.getDom(id));
20166 * Returns the actual DOM element
20167 * @method getElement
20168 * @param {String} id the id of the elment to get
20169 * @return {Object} The element
20170 * @deprecated use Roo.getDom instead
20173 getElement: function(id) {
20174 return Roo.getDom(id);
20178 * Returns the style property for the DOM element (i.e.,
20179 * document.getElById(id).style)
20181 * @param {String} id the id of the elment to get
20182 * @return {Object} The style property of the element
20183 * @deprecated use Roo.getDom instead
20186 getCss: function(id) {
20187 var el = Roo.getDom(id);
20188 return (el) ? el.style : null;
20192 * Inner class for cached elements
20193 * @class DragDropMgr.ElementWrapper
20198 ElementWrapper: function(el) {
20203 this.el = el || null;
20208 this.id = this.el && el.id;
20210 * A reference to the style property
20213 this.css = this.el && el.style;
20217 * Returns the X position of an html element
20219 * @param el the element for which to get the position
20220 * @return {int} the X coordinate
20222 * @deprecated use Roo.lib.Dom.getX instead
20225 getPosX: function(el) {
20226 return Roo.lib.Dom.getX(el);
20230 * Returns the Y position of an html element
20232 * @param el the element for which to get the position
20233 * @return {int} the Y coordinate
20234 * @deprecated use Roo.lib.Dom.getY instead
20237 getPosY: function(el) {
20238 return Roo.lib.Dom.getY(el);
20242 * Swap two nodes. In IE, we use the native method, for others we
20243 * emulate the IE behavior
20245 * @param n1 the first node to swap
20246 * @param n2 the other node to swap
20249 swapNode: function(n1, n2) {
20253 var p = n2.parentNode;
20254 var s = n2.nextSibling;
20257 p.insertBefore(n1, n2);
20258 } else if (n2 == n1.nextSibling) {
20259 p.insertBefore(n2, n1);
20261 n1.parentNode.replaceChild(n2, n1);
20262 p.insertBefore(n1, s);
20268 * Returns the current scroll position
20269 * @method getScroll
20273 getScroll: function () {
20274 var t, l, dde=document.documentElement, db=document.body;
20275 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20277 l = dde.scrollLeft;
20284 return { top: t, left: l };
20288 * Returns the specified element style property
20290 * @param {HTMLElement} el the element
20291 * @param {string} styleProp the style property
20292 * @return {string} The value of the style property
20293 * @deprecated use Roo.lib.Dom.getStyle
20296 getStyle: function(el, styleProp) {
20297 return Roo.fly(el).getStyle(styleProp);
20301 * Gets the scrollTop
20302 * @method getScrollTop
20303 * @return {int} the document's scrollTop
20306 getScrollTop: function () { return this.getScroll().top; },
20309 * Gets the scrollLeft
20310 * @method getScrollLeft
20311 * @return {int} the document's scrollTop
20314 getScrollLeft: function () { return this.getScroll().left; },
20317 * Sets the x/y position of an element to the location of the
20320 * @param {HTMLElement} moveEl The element to move
20321 * @param {HTMLElement} targetEl The position reference element
20324 moveToEl: function (moveEl, targetEl) {
20325 var aCoord = Roo.lib.Dom.getXY(targetEl);
20326 Roo.lib.Dom.setXY(moveEl, aCoord);
20330 * Numeric array sort function
20331 * @method numericSort
20334 numericSort: function(a, b) { return (a - b); },
20338 * @property _timeoutCount
20345 * Trying to make the load order less important. Without this we get
20346 * an error if this file is loaded before the Event Utility.
20347 * @method _addListeners
20351 _addListeners: function() {
20352 var DDM = Roo.dd.DDM;
20353 if ( Roo.lib.Event && document ) {
20356 if (DDM._timeoutCount > 2000) {
20358 setTimeout(DDM._addListeners, 10);
20359 if (document && document.body) {
20360 DDM._timeoutCount += 1;
20367 * Recursively searches the immediate parent and all child nodes for
20368 * the handle element in order to determine wheter or not it was
20370 * @method handleWasClicked
20371 * @param node the html element to inspect
20374 handleWasClicked: function(node, id) {
20375 if (this.isHandle(id, node.id)) {
20378 // check to see if this is a text node child of the one we want
20379 var p = node.parentNode;
20382 if (this.isHandle(id, p.id)) {
20397 // shorter alias, save a few bytes
20398 Roo.dd.DDM = Roo.dd.DragDropMgr;
20399 Roo.dd.DDM._addListeners();
20403 * Ext JS Library 1.1.1
20404 * Copyright(c) 2006-2007, Ext JS, LLC.
20406 * Originally Released Under LGPL - original licence link has changed is not relivant.
20409 * <script type="text/javascript">
20414 * A DragDrop implementation where the linked element follows the
20415 * mouse cursor during a drag.
20416 * @extends Roo.dd.DragDrop
20418 * @param {String} id the id of the linked element
20419 * @param {String} sGroup the group of related DragDrop items
20420 * @param {object} config an object containing configurable attributes
20421 * Valid properties for DD:
20424 Roo.dd.DD = function(id, sGroup, config) {
20426 this.init(id, sGroup, config);
20430 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20433 * When set to true, the utility automatically tries to scroll the browser
20434 * window wehn a drag and drop element is dragged near the viewport boundary.
20435 * Defaults to true.
20442 * Sets the pointer offset to the distance between the linked element's top
20443 * left corner and the location the element was clicked
20444 * @method autoOffset
20445 * @param {int} iPageX the X coordinate of the click
20446 * @param {int} iPageY the Y coordinate of the click
20448 autoOffset: function(iPageX, iPageY) {
20449 var x = iPageX - this.startPageX;
20450 var y = iPageY - this.startPageY;
20451 this.setDelta(x, y);
20455 * Sets the pointer offset. You can call this directly to force the
20456 * offset to be in a particular location (e.g., pass in 0,0 to set it
20457 * to the center of the object)
20459 * @param {int} iDeltaX the distance from the left
20460 * @param {int} iDeltaY the distance from the top
20462 setDelta: function(iDeltaX, iDeltaY) {
20463 this.deltaX = iDeltaX;
20464 this.deltaY = iDeltaY;
20468 * Sets the drag element to the location of the mousedown or click event,
20469 * maintaining the cursor location relative to the location on the element
20470 * that was clicked. Override this if you want to place the element in a
20471 * location other than where the cursor is.
20472 * @method setDragElPos
20473 * @param {int} iPageX the X coordinate of the mousedown or drag event
20474 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20476 setDragElPos: function(iPageX, iPageY) {
20477 // the first time we do this, we are going to check to make sure
20478 // the element has css positioning
20480 var el = this.getDragEl();
20481 this.alignElWithMouse(el, iPageX, iPageY);
20485 * Sets the element to the location of the mousedown or click event,
20486 * maintaining the cursor location relative to the location on the element
20487 * that was clicked. Override this if you want to place the element in a
20488 * location other than where the cursor is.
20489 * @method alignElWithMouse
20490 * @param {HTMLElement} el the element to move
20491 * @param {int} iPageX the X coordinate of the mousedown or drag event
20492 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20494 alignElWithMouse: function(el, iPageX, iPageY) {
20495 var oCoord = this.getTargetCoord(iPageX, iPageY);
20496 var fly = el.dom ? el : Roo.fly(el);
20497 if (!this.deltaSetXY) {
20498 var aCoord = [oCoord.x, oCoord.y];
20500 var newLeft = fly.getLeft(true);
20501 var newTop = fly.getTop(true);
20502 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20504 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20507 this.cachePosition(oCoord.x, oCoord.y);
20508 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20513 * Saves the most recent position so that we can reset the constraints and
20514 * tick marks on-demand. We need to know this so that we can calculate the
20515 * number of pixels the element is offset from its original position.
20516 * @method cachePosition
20517 * @param iPageX the current x position (optional, this just makes it so we
20518 * don't have to look it up again)
20519 * @param iPageY the current y position (optional, this just makes it so we
20520 * don't have to look it up again)
20522 cachePosition: function(iPageX, iPageY) {
20524 this.lastPageX = iPageX;
20525 this.lastPageY = iPageY;
20527 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20528 this.lastPageX = aCoord[0];
20529 this.lastPageY = aCoord[1];
20534 * Auto-scroll the window if the dragged object has been moved beyond the
20535 * visible window boundary.
20536 * @method autoScroll
20537 * @param {int} x the drag element's x position
20538 * @param {int} y the drag element's y position
20539 * @param {int} h the height of the drag element
20540 * @param {int} w the width of the drag element
20543 autoScroll: function(x, y, h, w) {
20546 // The client height
20547 var clientH = Roo.lib.Dom.getViewWidth();
20549 // The client width
20550 var clientW = Roo.lib.Dom.getViewHeight();
20552 // The amt scrolled down
20553 var st = this.DDM.getScrollTop();
20555 // The amt scrolled right
20556 var sl = this.DDM.getScrollLeft();
20558 // Location of the bottom of the element
20561 // Location of the right of the element
20564 // The distance from the cursor to the bottom of the visible area,
20565 // adjusted so that we don't scroll if the cursor is beyond the
20566 // element drag constraints
20567 var toBot = (clientH + st - y - this.deltaY);
20569 // The distance from the cursor to the right of the visible area
20570 var toRight = (clientW + sl - x - this.deltaX);
20573 // How close to the edge the cursor must be before we scroll
20574 // var thresh = (document.all) ? 100 : 40;
20577 // How many pixels to scroll per autoscroll op. This helps to reduce
20578 // clunky scrolling. IE is more sensitive about this ... it needs this
20579 // value to be higher.
20580 var scrAmt = (document.all) ? 80 : 30;
20582 // Scroll down if we are near the bottom of the visible page and the
20583 // obj extends below the crease
20584 if ( bot > clientH && toBot < thresh ) {
20585 window.scrollTo(sl, st + scrAmt);
20588 // Scroll up if the window is scrolled down and the top of the object
20589 // goes above the top border
20590 if ( y < st && st > 0 && y - st < thresh ) {
20591 window.scrollTo(sl, st - scrAmt);
20594 // Scroll right if the obj is beyond the right border and the cursor is
20595 // near the border.
20596 if ( right > clientW && toRight < thresh ) {
20597 window.scrollTo(sl + scrAmt, st);
20600 // Scroll left if the window has been scrolled to the right and the obj
20601 // extends past the left border
20602 if ( x < sl && sl > 0 && x - sl < thresh ) {
20603 window.scrollTo(sl - scrAmt, st);
20609 * Finds the location the element should be placed if we want to move
20610 * it to where the mouse location less the click offset would place us.
20611 * @method getTargetCoord
20612 * @param {int} iPageX the X coordinate of the click
20613 * @param {int} iPageY the Y coordinate of the click
20614 * @return an object that contains the coordinates (Object.x and Object.y)
20617 getTargetCoord: function(iPageX, iPageY) {
20620 var x = iPageX - this.deltaX;
20621 var y = iPageY - this.deltaY;
20623 if (this.constrainX) {
20624 if (x < this.minX) { x = this.minX; }
20625 if (x > this.maxX) { x = this.maxX; }
20628 if (this.constrainY) {
20629 if (y < this.minY) { y = this.minY; }
20630 if (y > this.maxY) { y = this.maxY; }
20633 x = this.getTick(x, this.xTicks);
20634 y = this.getTick(y, this.yTicks);
20641 * Sets up config options specific to this class. Overrides
20642 * Roo.dd.DragDrop, but all versions of this method through the
20643 * inheritance chain are called
20645 applyConfig: function() {
20646 Roo.dd.DD.superclass.applyConfig.call(this);
20647 this.scroll = (this.config.scroll !== false);
20651 * Event that fires prior to the onMouseDown event. Overrides
20654 b4MouseDown: function(e) {
20655 // this.resetConstraints();
20656 this.autoOffset(e.getPageX(),
20661 * Event that fires prior to the onDrag event. Overrides
20664 b4Drag: function(e) {
20665 this.setDragElPos(e.getPageX(),
20669 toString: function() {
20670 return ("DD " + this.id);
20673 //////////////////////////////////////////////////////////////////////////
20674 // Debugging ygDragDrop events that can be overridden
20675 //////////////////////////////////////////////////////////////////////////
20677 startDrag: function(x, y) {
20680 onDrag: function(e) {
20683 onDragEnter: function(e, id) {
20686 onDragOver: function(e, id) {
20689 onDragOut: function(e, id) {
20692 onDragDrop: function(e, id) {
20695 endDrag: function(e) {
20702 * Ext JS Library 1.1.1
20703 * Copyright(c) 2006-2007, Ext JS, LLC.
20705 * Originally Released Under LGPL - original licence link has changed is not relivant.
20708 * <script type="text/javascript">
20712 * @class Roo.dd.DDProxy
20713 * A DragDrop implementation that inserts an empty, bordered div into
20714 * the document that follows the cursor during drag operations. At the time of
20715 * the click, the frame div is resized to the dimensions of the linked html
20716 * element, and moved to the exact location of the linked element.
20718 * References to the "frame" element refer to the single proxy element that
20719 * was created to be dragged in place of all DDProxy elements on the
20722 * @extends Roo.dd.DD
20724 * @param {String} id the id of the linked html element
20725 * @param {String} sGroup the group of related DragDrop objects
20726 * @param {object} config an object containing configurable attributes
20727 * Valid properties for DDProxy in addition to those in DragDrop:
20728 * resizeFrame, centerFrame, dragElId
20730 Roo.dd.DDProxy = function(id, sGroup, config) {
20732 this.init(id, sGroup, config);
20738 * The default drag frame div id
20739 * @property Roo.dd.DDProxy.dragElId
20743 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20745 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20748 * By default we resize the drag frame to be the same size as the element
20749 * we want to drag (this is to get the frame effect). We can turn it off
20750 * if we want a different behavior.
20751 * @property resizeFrame
20757 * By default the frame is positioned exactly where the drag element is, so
20758 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20759 * you do not have constraints on the obj is to have the drag frame centered
20760 * around the cursor. Set centerFrame to true for this effect.
20761 * @property centerFrame
20764 centerFrame: false,
20767 * Creates the proxy element if it does not yet exist
20768 * @method createFrame
20770 createFrame: function() {
20772 var body = document.body;
20774 if (!body || !body.firstChild) {
20775 setTimeout( function() { self.createFrame(); }, 50 );
20779 var div = this.getDragEl();
20782 div = document.createElement("div");
20783 div.id = this.dragElId;
20786 s.position = "absolute";
20787 s.visibility = "hidden";
20789 s.border = "2px solid #aaa";
20792 // appendChild can blow up IE if invoked prior to the window load event
20793 // while rendering a table. It is possible there are other scenarios
20794 // that would cause this to happen as well.
20795 body.insertBefore(div, body.firstChild);
20800 * Initialization for the drag frame element. Must be called in the
20801 * constructor of all subclasses
20802 * @method initFrame
20804 initFrame: function() {
20805 this.createFrame();
20808 applyConfig: function() {
20809 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20811 this.resizeFrame = (this.config.resizeFrame !== false);
20812 this.centerFrame = (this.config.centerFrame);
20813 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20817 * Resizes the drag frame to the dimensions of the clicked object, positions
20818 * it over the object, and finally displays it
20819 * @method showFrame
20820 * @param {int} iPageX X click position
20821 * @param {int} iPageY Y click position
20824 showFrame: function(iPageX, iPageY) {
20825 var el = this.getEl();
20826 var dragEl = this.getDragEl();
20827 var s = dragEl.style;
20829 this._resizeProxy();
20831 if (this.centerFrame) {
20832 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20833 Math.round(parseInt(s.height, 10)/2) );
20836 this.setDragElPos(iPageX, iPageY);
20838 Roo.fly(dragEl).show();
20842 * The proxy is automatically resized to the dimensions of the linked
20843 * element when a drag is initiated, unless resizeFrame is set to false
20844 * @method _resizeProxy
20847 _resizeProxy: function() {
20848 if (this.resizeFrame) {
20849 var el = this.getEl();
20850 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20854 // overrides Roo.dd.DragDrop
20855 b4MouseDown: function(e) {
20856 var x = e.getPageX();
20857 var y = e.getPageY();
20858 this.autoOffset(x, y);
20859 this.setDragElPos(x, y);
20862 // overrides Roo.dd.DragDrop
20863 b4StartDrag: function(x, y) {
20864 // show the drag frame
20865 this.showFrame(x, y);
20868 // overrides Roo.dd.DragDrop
20869 b4EndDrag: function(e) {
20870 Roo.fly(this.getDragEl()).hide();
20873 // overrides Roo.dd.DragDrop
20874 // By default we try to move the element to the last location of the frame.
20875 // This is so that the default behavior mirrors that of Roo.dd.DD.
20876 endDrag: function(e) {
20878 var lel = this.getEl();
20879 var del = this.getDragEl();
20881 // Show the drag frame briefly so we can get its position
20882 del.style.visibility = "";
20885 // Hide the linked element before the move to get around a Safari
20887 lel.style.visibility = "hidden";
20888 Roo.dd.DDM.moveToEl(lel, del);
20889 del.style.visibility = "hidden";
20890 lel.style.visibility = "";
20895 beforeMove : function(){
20899 afterDrag : function(){
20903 toString: function() {
20904 return ("DDProxy " + this.id);
20910 * Ext JS Library 1.1.1
20911 * Copyright(c) 2006-2007, Ext JS, LLC.
20913 * Originally Released Under LGPL - original licence link has changed is not relivant.
20916 * <script type="text/javascript">
20920 * @class Roo.dd.DDTarget
20921 * A DragDrop implementation that does not move, but can be a drop
20922 * target. You would get the same result by simply omitting implementation
20923 * for the event callbacks, but this way we reduce the processing cost of the
20924 * event listener and the callbacks.
20925 * @extends Roo.dd.DragDrop
20927 * @param {String} id the id of the element that is a drop target
20928 * @param {String} sGroup the group of related DragDrop objects
20929 * @param {object} config an object containing configurable attributes
20930 * Valid properties for DDTarget in addition to those in
20934 Roo.dd.DDTarget = function(id, sGroup, config) {
20936 this.initTarget(id, sGroup, config);
20938 if (config.listeners || config.events) {
20939 Roo.dd.DragDrop.superclass.constructor.call(this, {
20940 listeners : config.listeners || {},
20941 events : config.events || {}
20946 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20947 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20948 toString: function() {
20949 return ("DDTarget " + this.id);
20954 * Ext JS Library 1.1.1
20955 * Copyright(c) 2006-2007, Ext JS, LLC.
20957 * Originally Released Under LGPL - original licence link has changed is not relivant.
20960 * <script type="text/javascript">
20965 * @class Roo.dd.ScrollManager
20966 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20967 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20970 Roo.dd.ScrollManager = function(){
20971 var ddm = Roo.dd.DragDropMgr;
20978 var onStop = function(e){
20983 var triggerRefresh = function(){
20984 if(ddm.dragCurrent){
20985 ddm.refreshCache(ddm.dragCurrent.groups);
20989 var doScroll = function(){
20990 if(ddm.dragCurrent){
20991 var dds = Roo.dd.ScrollManager;
20993 if(proc.el.scroll(proc.dir, dds.increment)){
20997 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21002 var clearProc = function(){
21004 clearInterval(proc.id);
21011 var startProc = function(el, dir){
21012 Roo.log('scroll startproc');
21016 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21019 var onFire = function(e, isDrop){
21021 if(isDrop || !ddm.dragCurrent){ return; }
21022 var dds = Roo.dd.ScrollManager;
21023 if(!dragEl || dragEl != ddm.dragCurrent){
21024 dragEl = ddm.dragCurrent;
21025 // refresh regions on drag start
21026 dds.refreshCache();
21029 var xy = Roo.lib.Event.getXY(e);
21030 var pt = new Roo.lib.Point(xy[0], xy[1]);
21031 for(var id in els){
21032 var el = els[id], r = el._region;
21033 if(r && r.contains(pt) && el.isScrollable()){
21034 if(r.bottom - pt.y <= dds.thresh){
21036 startProc(el, "down");
21039 }else if(r.right - pt.x <= dds.thresh){
21041 startProc(el, "left");
21044 }else if(pt.y - r.top <= dds.thresh){
21046 startProc(el, "up");
21049 }else if(pt.x - r.left <= dds.thresh){
21051 startProc(el, "right");
21060 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21061 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21065 * Registers new overflow element(s) to auto scroll
21066 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21068 register : function(el){
21069 if(el instanceof Array){
21070 for(var i = 0, len = el.length; i < len; i++) {
21071 this.register(el[i]);
21077 Roo.dd.ScrollManager.els = els;
21081 * Unregisters overflow element(s) so they are no longer scrolled
21082 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21084 unregister : function(el){
21085 if(el instanceof Array){
21086 for(var i = 0, len = el.length; i < len; i++) {
21087 this.unregister(el[i]);
21096 * The number of pixels from the edge of a container the pointer needs to be to
21097 * trigger scrolling (defaults to 25)
21103 * The number of pixels to scroll in each scroll increment (defaults to 50)
21109 * The frequency of scrolls in milliseconds (defaults to 500)
21115 * True to animate the scroll (defaults to true)
21121 * The animation duration in seconds -
21122 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21128 * Manually trigger a cache refresh.
21130 refreshCache : function(){
21131 for(var id in els){
21132 if(typeof els[id] == 'object'){ // for people extending the object prototype
21133 els[id]._region = els[id].getRegion();
21140 * Ext JS Library 1.1.1
21141 * Copyright(c) 2006-2007, Ext JS, LLC.
21143 * Originally Released Under LGPL - original licence link has changed is not relivant.
21146 * <script type="text/javascript">
21151 * @class Roo.dd.Registry
21152 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21153 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21156 Roo.dd.Registry = function(){
21159 var autoIdSeed = 0;
21161 var getId = function(el, autogen){
21162 if(typeof el == "string"){
21166 if(!id && autogen !== false){
21167 id = "roodd-" + (++autoIdSeed);
21175 * Register a drag drop element
21176 * @param {String|HTMLElement} element The id or DOM node to register
21177 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21178 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21179 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21180 * populated in the data object (if applicable):
21182 Value Description<br />
21183 --------- ------------------------------------------<br />
21184 handles Array of DOM nodes that trigger dragging<br />
21185 for the element being registered<br />
21186 isHandle True if the element passed in triggers<br />
21187 dragging itself, else false
21190 register : function(el, data){
21192 if(typeof el == "string"){
21193 el = document.getElementById(el);
21196 elements[getId(el)] = data;
21197 if(data.isHandle !== false){
21198 handles[data.ddel.id] = data;
21201 var hs = data.handles;
21202 for(var i = 0, len = hs.length; i < len; i++){
21203 handles[getId(hs[i])] = data;
21209 * Unregister a drag drop element
21210 * @param {String|HTMLElement} element The id or DOM node to unregister
21212 unregister : function(el){
21213 var id = getId(el, false);
21214 var data = elements[id];
21216 delete elements[id];
21218 var hs = data.handles;
21219 for(var i = 0, len = hs.length; i < len; i++){
21220 delete handles[getId(hs[i], false)];
21227 * Returns the handle registered for a DOM Node by id
21228 * @param {String|HTMLElement} id The DOM node or id to look up
21229 * @return {Object} handle The custom handle data
21231 getHandle : function(id){
21232 if(typeof id != "string"){ // must be element?
21235 return handles[id];
21239 * Returns the handle that is registered for the DOM node that is the target of the event
21240 * @param {Event} e The event
21241 * @return {Object} handle The custom handle data
21243 getHandleFromEvent : function(e){
21244 var t = Roo.lib.Event.getTarget(e);
21245 return t ? handles[t.id] : null;
21249 * Returns a custom data object that is registered for a DOM node by id
21250 * @param {String|HTMLElement} id The DOM node or id to look up
21251 * @return {Object} data The custom data
21253 getTarget : function(id){
21254 if(typeof id != "string"){ // must be element?
21257 return elements[id];
21261 * Returns a custom data object that is registered for the DOM node that is the target of the event
21262 * @param {Event} e The event
21263 * @return {Object} data The custom data
21265 getTargetFromEvent : function(e){
21266 var t = Roo.lib.Event.getTarget(e);
21267 return t ? elements[t.id] || handles[t.id] : null;
21272 * Ext JS Library 1.1.1
21273 * Copyright(c) 2006-2007, Ext JS, LLC.
21275 * Originally Released Under LGPL - original licence link has changed is not relivant.
21278 * <script type="text/javascript">
21283 * @class Roo.dd.StatusProxy
21284 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21285 * default drag proxy used by all Roo.dd components.
21287 * @param {Object} config
21289 Roo.dd.StatusProxy = function(config){
21290 Roo.apply(this, config);
21291 this.id = this.id || Roo.id();
21292 this.el = new Roo.Layer({
21294 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21295 {tag: "div", cls: "x-dd-drop-icon"},
21296 {tag: "div", cls: "x-dd-drag-ghost"}
21299 shadow: !config || config.shadow !== false
21301 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21302 this.dropStatus = this.dropNotAllowed;
21305 Roo.dd.StatusProxy.prototype = {
21307 * @cfg {String} dropAllowed
21308 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21310 dropAllowed : "x-dd-drop-ok",
21312 * @cfg {String} dropNotAllowed
21313 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21315 dropNotAllowed : "x-dd-drop-nodrop",
21318 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21319 * over the current target element.
21320 * @param {String} cssClass The css class for the new drop status indicator image
21322 setStatus : function(cssClass){
21323 cssClass = cssClass || this.dropNotAllowed;
21324 if(this.dropStatus != cssClass){
21325 this.el.replaceClass(this.dropStatus, cssClass);
21326 this.dropStatus = cssClass;
21331 * Resets the status indicator to the default dropNotAllowed value
21332 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21334 reset : function(clearGhost){
21335 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21336 this.dropStatus = this.dropNotAllowed;
21338 this.ghost.update("");
21343 * Updates the contents of the ghost element
21344 * @param {String} html The html that will replace the current innerHTML of the ghost element
21346 update : function(html){
21347 if(typeof html == "string"){
21348 this.ghost.update(html);
21350 this.ghost.update("");
21351 html.style.margin = "0";
21352 this.ghost.dom.appendChild(html);
21354 // ensure float = none set?? cant remember why though.
21355 var el = this.ghost.dom.firstChild;
21357 Roo.fly(el).setStyle('float', 'none');
21362 * Returns the underlying proxy {@link Roo.Layer}
21363 * @return {Roo.Layer} el
21365 getEl : function(){
21370 * Returns the ghost element
21371 * @return {Roo.Element} el
21373 getGhost : function(){
21379 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21381 hide : function(clear){
21389 * Stops the repair animation if it's currently running
21392 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21398 * Displays this proxy
21405 * Force the Layer to sync its shadow and shim positions to the element
21412 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21413 * invalid drop operation by the item being dragged.
21414 * @param {Array} xy The XY position of the element ([x, y])
21415 * @param {Function} callback The function to call after the repair is complete
21416 * @param {Object} scope The scope in which to execute the callback
21418 repair : function(xy, callback, scope){
21419 this.callback = callback;
21420 this.scope = scope;
21421 if(xy && this.animRepair !== false){
21422 this.el.addClass("x-dd-drag-repair");
21423 this.el.hideUnders(true);
21424 this.anim = this.el.shift({
21425 duration: this.repairDuration || .5,
21429 callback: this.afterRepair,
21433 this.afterRepair();
21438 afterRepair : function(){
21440 if(typeof this.callback == "function"){
21441 this.callback.call(this.scope || this);
21443 this.callback = null;
21448 * Ext JS Library 1.1.1
21449 * Copyright(c) 2006-2007, Ext JS, LLC.
21451 * Originally Released Under LGPL - original licence link has changed is not relivant.
21454 * <script type="text/javascript">
21458 * @class Roo.dd.DragSource
21459 * @extends Roo.dd.DDProxy
21460 * A simple class that provides the basic implementation needed to make any element draggable.
21462 * @param {String/HTMLElement/Element} el The container element
21463 * @param {Object} config
21465 Roo.dd.DragSource = function(el, config){
21466 this.el = Roo.get(el);
21467 this.dragData = {};
21469 Roo.apply(this, config);
21472 this.proxy = new Roo.dd.StatusProxy();
21475 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21476 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21478 this.dragging = false;
21481 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21483 * @cfg {String} dropAllowed
21484 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21486 dropAllowed : "x-dd-drop-ok",
21488 * @cfg {String} dropNotAllowed
21489 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21491 dropNotAllowed : "x-dd-drop-nodrop",
21494 * Returns the data object associated with this drag source
21495 * @return {Object} data An object containing arbitrary data
21497 getDragData : function(e){
21498 return this.dragData;
21502 onDragEnter : function(e, id){
21503 var target = Roo.dd.DragDropMgr.getDDById(id);
21504 this.cachedTarget = target;
21505 if(this.beforeDragEnter(target, e, id) !== false){
21506 if(target.isNotifyTarget){
21507 var status = target.notifyEnter(this, e, this.dragData);
21508 this.proxy.setStatus(status);
21510 this.proxy.setStatus(this.dropAllowed);
21513 if(this.afterDragEnter){
21515 * An empty function by default, but provided so that you can perform a custom action
21516 * when the dragged item enters the drop target by providing an implementation.
21517 * @param {Roo.dd.DragDrop} target The drop target
21518 * @param {Event} e The event object
21519 * @param {String} id The id of the dragged element
21520 * @method afterDragEnter
21522 this.afterDragEnter(target, e, id);
21528 * An empty function by default, but provided so that you can perform a custom action
21529 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21530 * @param {Roo.dd.DragDrop} target The drop target
21531 * @param {Event} e The event object
21532 * @param {String} id The id of the dragged element
21533 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21535 beforeDragEnter : function(target, e, id){
21540 alignElWithMouse: function() {
21541 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21546 onDragOver : function(e, id){
21547 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21548 if(this.beforeDragOver(target, e, id) !== false){
21549 if(target.isNotifyTarget){
21550 var status = target.notifyOver(this, e, this.dragData);
21551 this.proxy.setStatus(status);
21554 if(this.afterDragOver){
21556 * An empty function by default, but provided so that you can perform a custom action
21557 * while the dragged item is over the drop target by providing an implementation.
21558 * @param {Roo.dd.DragDrop} target The drop target
21559 * @param {Event} e The event object
21560 * @param {String} id The id of the dragged element
21561 * @method afterDragOver
21563 this.afterDragOver(target, e, id);
21569 * An empty function by default, but provided so that you can perform a custom action
21570 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21571 * @param {Roo.dd.DragDrop} target The drop target
21572 * @param {Event} e The event object
21573 * @param {String} id The id of the dragged element
21574 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21576 beforeDragOver : function(target, e, id){
21581 onDragOut : function(e, id){
21582 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21583 if(this.beforeDragOut(target, e, id) !== false){
21584 if(target.isNotifyTarget){
21585 target.notifyOut(this, e, this.dragData);
21587 this.proxy.reset();
21588 if(this.afterDragOut){
21590 * An empty function by default, but provided so that you can perform a custom action
21591 * after the dragged item is dragged out of the target without dropping.
21592 * @param {Roo.dd.DragDrop} target The drop target
21593 * @param {Event} e The event object
21594 * @param {String} id The id of the dragged element
21595 * @method afterDragOut
21597 this.afterDragOut(target, e, id);
21600 this.cachedTarget = null;
21604 * An empty function by default, but provided so that you can perform a custom action before the dragged
21605 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21606 * @param {Roo.dd.DragDrop} target The drop target
21607 * @param {Event} e The event object
21608 * @param {String} id The id of the dragged element
21609 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21611 beforeDragOut : function(target, e, id){
21616 onDragDrop : function(e, id){
21617 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21618 if(this.beforeDragDrop(target, e, id) !== false){
21619 if(target.isNotifyTarget){
21620 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21621 this.onValidDrop(target, e, id);
21623 this.onInvalidDrop(target, e, id);
21626 this.onValidDrop(target, e, id);
21629 if(this.afterDragDrop){
21631 * An empty function by default, but provided so that you can perform a custom action
21632 * after a valid drag drop has occurred by providing an implementation.
21633 * @param {Roo.dd.DragDrop} target The drop target
21634 * @param {Event} e The event object
21635 * @param {String} id The id of the dropped element
21636 * @method afterDragDrop
21638 this.afterDragDrop(target, e, id);
21641 delete this.cachedTarget;
21645 * An empty function by default, but provided so that you can perform a custom action before the dragged
21646 * item is dropped onto the target and optionally cancel the onDragDrop.
21647 * @param {Roo.dd.DragDrop} target The drop target
21648 * @param {Event} e The event object
21649 * @param {String} id The id of the dragged element
21650 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21652 beforeDragDrop : function(target, e, id){
21657 onValidDrop : function(target, e, id){
21659 if(this.afterValidDrop){
21661 * An empty function by default, but provided so that you can perform a custom action
21662 * after a valid drop has occurred by providing an implementation.
21663 * @param {Object} target The target DD
21664 * @param {Event} e The event object
21665 * @param {String} id The id of the dropped element
21666 * @method afterInvalidDrop
21668 this.afterValidDrop(target, e, id);
21673 getRepairXY : function(e, data){
21674 return this.el.getXY();
21678 onInvalidDrop : function(target, e, id){
21679 this.beforeInvalidDrop(target, e, id);
21680 if(this.cachedTarget){
21681 if(this.cachedTarget.isNotifyTarget){
21682 this.cachedTarget.notifyOut(this, e, this.dragData);
21684 this.cacheTarget = null;
21686 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21688 if(this.afterInvalidDrop){
21690 * An empty function by default, but provided so that you can perform a custom action
21691 * after an invalid drop has occurred by providing an implementation.
21692 * @param {Event} e The event object
21693 * @param {String} id The id of the dropped element
21694 * @method afterInvalidDrop
21696 this.afterInvalidDrop(e, id);
21701 afterRepair : function(){
21703 this.el.highlight(this.hlColor || "c3daf9");
21705 this.dragging = false;
21709 * An empty function by default, but provided so that you can perform a custom action after an invalid
21710 * drop has occurred.
21711 * @param {Roo.dd.DragDrop} target The drop target
21712 * @param {Event} e The event object
21713 * @param {String} id The id of the dragged element
21714 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21716 beforeInvalidDrop : function(target, e, id){
21721 handleMouseDown : function(e){
21722 if(this.dragging) {
21725 var data = this.getDragData(e);
21726 if(data && this.onBeforeDrag(data, e) !== false){
21727 this.dragData = data;
21729 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21734 * An empty function by default, but provided so that you can perform a custom action before the initial
21735 * drag event begins and optionally cancel it.
21736 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21737 * @param {Event} e The event object
21738 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21740 onBeforeDrag : function(data, e){
21745 * An empty function by default, but provided so that you can perform a custom action once the initial
21746 * drag event has begun. The drag cannot be canceled from this function.
21747 * @param {Number} x The x position of the click on the dragged object
21748 * @param {Number} y The y position of the click on the dragged object
21750 onStartDrag : Roo.emptyFn,
21752 // private - YUI override
21753 startDrag : function(x, y){
21754 this.proxy.reset();
21755 this.dragging = true;
21756 this.proxy.update("");
21757 this.onInitDrag(x, y);
21762 onInitDrag : function(x, y){
21763 var clone = this.el.dom.cloneNode(true);
21764 clone.id = Roo.id(); // prevent duplicate ids
21765 this.proxy.update(clone);
21766 this.onStartDrag(x, y);
21771 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21772 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21774 getProxy : function(){
21779 * Hides the drag source's {@link Roo.dd.StatusProxy}
21781 hideProxy : function(){
21783 this.proxy.reset(true);
21784 this.dragging = false;
21788 triggerCacheRefresh : function(){
21789 Roo.dd.DDM.refreshCache(this.groups);
21792 // private - override to prevent hiding
21793 b4EndDrag: function(e) {
21796 // private - override to prevent moving
21797 endDrag : function(e){
21798 this.onEndDrag(this.dragData, e);
21802 onEndDrag : function(data, e){
21805 // private - pin to cursor
21806 autoOffset : function(x, y) {
21807 this.setDelta(-12, -20);
21811 * Ext JS Library 1.1.1
21812 * Copyright(c) 2006-2007, Ext JS, LLC.
21814 * Originally Released Under LGPL - original licence link has changed is not relivant.
21817 * <script type="text/javascript">
21822 * @class Roo.dd.DropTarget
21823 * @extends Roo.dd.DDTarget
21824 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21825 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21827 * @param {String/HTMLElement/Element} el The container element
21828 * @param {Object} config
21830 Roo.dd.DropTarget = function(el, config){
21831 this.el = Roo.get(el);
21833 var listeners = false; ;
21834 if (config && config.listeners) {
21835 listeners= config.listeners;
21836 delete config.listeners;
21838 Roo.apply(this, config);
21840 if(this.containerScroll){
21841 Roo.dd.ScrollManager.register(this.el);
21845 * @scope Roo.dd.DropTarget
21850 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21851 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21852 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21854 * IMPORTANT : it should set this.overClass and this.dropAllowed
21856 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21857 * @param {Event} e The event
21858 * @param {Object} data An object containing arbitrary data supplied by the drag source
21864 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21865 * This method will be called on every mouse movement while the drag source is over the drop target.
21866 * This default implementation simply returns the dropAllowed config value.
21868 * IMPORTANT : it should set this.dropAllowed
21870 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21871 * @param {Event} e The event
21872 * @param {Object} data An object containing arbitrary data supplied by the drag source
21878 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21879 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21880 * overClass (if any) from the drop element.
21882 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21883 * @param {Event} e The event
21884 * @param {Object} data An object containing arbitrary data supplied by the drag source
21890 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21891 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21892 * implementation that does something to process the drop event and returns true so that the drag source's
21893 * repair action does not run.
21895 * IMPORTANT : it should set this.success
21897 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21898 * @param {Event} e The event
21899 * @param {Object} data An object containing arbitrary data supplied by the drag source
21905 Roo.dd.DropTarget.superclass.constructor.call( this,
21907 this.ddGroup || this.group,
21910 listeners : listeners || {}
21918 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21920 * @cfg {String} overClass
21921 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21924 * @cfg {String} ddGroup
21925 * The drag drop group to handle drop events for
21929 * @cfg {String} dropAllowed
21930 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21932 dropAllowed : "x-dd-drop-ok",
21934 * @cfg {String} dropNotAllowed
21935 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21937 dropNotAllowed : "x-dd-drop-nodrop",
21939 * @cfg {boolean} success
21940 * set this after drop listener..
21944 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21945 * if the drop point is valid for over/enter..
21952 isNotifyTarget : true,
21957 notifyEnter : function(dd, e, data)
21960 this.fireEvent('enter', dd, e, data);
21961 if(this.overClass){
21962 this.el.addClass(this.overClass);
21964 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21965 this.valid ? this.dropAllowed : this.dropNotAllowed
21972 notifyOver : function(dd, e, data)
21975 this.fireEvent('over', dd, e, data);
21976 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21977 this.valid ? this.dropAllowed : this.dropNotAllowed
21984 notifyOut : function(dd, e, data)
21986 this.fireEvent('out', dd, e, data);
21987 if(this.overClass){
21988 this.el.removeClass(this.overClass);
21995 notifyDrop : function(dd, e, data)
21997 this.success = false;
21998 this.fireEvent('drop', dd, e, data);
21999 return this.success;
22003 * Ext JS Library 1.1.1
22004 * Copyright(c) 2006-2007, Ext JS, LLC.
22006 * Originally Released Under LGPL - original licence link has changed is not relivant.
22009 * <script type="text/javascript">
22014 * @class Roo.dd.DragZone
22015 * @extends Roo.dd.DragSource
22016 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22017 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22019 * @param {String/HTMLElement/Element} el The container element
22020 * @param {Object} config
22022 Roo.dd.DragZone = function(el, config){
22023 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22024 if(this.containerScroll){
22025 Roo.dd.ScrollManager.register(this.el);
22029 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22031 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22032 * for auto scrolling during drag operations.
22035 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22036 * method after a failed drop (defaults to "c3daf9" - light blue)
22040 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22041 * for a valid target to drag based on the mouse down. Override this method
22042 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22043 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22044 * @param {EventObject} e The mouse down event
22045 * @return {Object} The dragData
22047 getDragData : function(e){
22048 return Roo.dd.Registry.getHandleFromEvent(e);
22052 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22053 * this.dragData.ddel
22054 * @param {Number} x The x position of the click on the dragged object
22055 * @param {Number} y The y position of the click on the dragged object
22056 * @return {Boolean} true to continue the drag, false to cancel
22058 onInitDrag : function(x, y){
22059 this.proxy.update(this.dragData.ddel.cloneNode(true));
22060 this.onStartDrag(x, y);
22065 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22067 afterRepair : function(){
22069 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22071 this.dragging = false;
22075 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22076 * the XY of this.dragData.ddel
22077 * @param {EventObject} e The mouse up event
22078 * @return {Array} The xy location (e.g. [100, 200])
22080 getRepairXY : function(e){
22081 return Roo.Element.fly(this.dragData.ddel).getXY();
22085 * Ext JS Library 1.1.1
22086 * Copyright(c) 2006-2007, Ext JS, LLC.
22088 * Originally Released Under LGPL - original licence link has changed is not relivant.
22091 * <script type="text/javascript">
22094 * @class Roo.dd.DropZone
22095 * @extends Roo.dd.DropTarget
22096 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22097 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22099 * @param {String/HTMLElement/Element} el The container element
22100 * @param {Object} config
22102 Roo.dd.DropZone = function(el, config){
22103 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22106 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22108 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22109 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22110 * provide your own custom lookup.
22111 * @param {Event} e The event
22112 * @return {Object} data The custom data
22114 getTargetFromEvent : function(e){
22115 return Roo.dd.Registry.getTargetFromEvent(e);
22119 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22120 * that it has registered. This method has no default implementation and should be overridden to provide
22121 * node-specific processing if necessary.
22122 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22123 * {@link #getTargetFromEvent} for this node)
22124 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22125 * @param {Event} e The event
22126 * @param {Object} data An object containing arbitrary data supplied by the drag source
22128 onNodeEnter : function(n, dd, e, data){
22133 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22134 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22135 * overridden to provide the proper feedback.
22136 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22137 * {@link #getTargetFromEvent} for this node)
22138 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22139 * @param {Event} e The event
22140 * @param {Object} data An object containing arbitrary data supplied by the drag source
22141 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22142 * underlying {@link Roo.dd.StatusProxy} can be updated
22144 onNodeOver : function(n, dd, e, data){
22145 return this.dropAllowed;
22149 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22150 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22151 * node-specific processing if necessary.
22152 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22153 * {@link #getTargetFromEvent} for this node)
22154 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22155 * @param {Event} e The event
22156 * @param {Object} data An object containing arbitrary data supplied by the drag source
22158 onNodeOut : function(n, dd, e, data){
22163 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22164 * the drop node. The default implementation returns false, so it should be overridden to provide the
22165 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22166 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22167 * {@link #getTargetFromEvent} for this node)
22168 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22169 * @param {Event} e The event
22170 * @param {Object} data An object containing arbitrary data supplied by the drag source
22171 * @return {Boolean} True if the drop was valid, else false
22173 onNodeDrop : function(n, dd, e, data){
22178 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22179 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22180 * it should be overridden to provide the proper feedback if necessary.
22181 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22182 * @param {Event} e The event
22183 * @param {Object} data An object containing arbitrary data supplied by the drag source
22184 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22185 * underlying {@link Roo.dd.StatusProxy} can be updated
22187 onContainerOver : function(dd, e, data){
22188 return this.dropNotAllowed;
22192 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22193 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22194 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22195 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22196 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22197 * @param {Event} e The event
22198 * @param {Object} data An object containing arbitrary data supplied by the drag source
22199 * @return {Boolean} True if the drop was valid, else false
22201 onContainerDrop : function(dd, e, data){
22206 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22207 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22208 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22209 * you should override this method and provide a custom implementation.
22210 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22211 * @param {Event} e The event
22212 * @param {Object} data An object containing arbitrary data supplied by the drag source
22213 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22214 * underlying {@link Roo.dd.StatusProxy} can be updated
22216 notifyEnter : function(dd, e, data){
22217 return this.dropNotAllowed;
22221 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22222 * This method will be called on every mouse movement while the drag source is over the drop zone.
22223 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22224 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22225 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22226 * registered node, it will call {@link #onContainerOver}.
22227 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22228 * @param {Event} e The event
22229 * @param {Object} data An object containing arbitrary data supplied by the drag source
22230 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22231 * underlying {@link Roo.dd.StatusProxy} can be updated
22233 notifyOver : function(dd, e, data){
22234 var n = this.getTargetFromEvent(e);
22235 if(!n){ // not over valid drop target
22236 if(this.lastOverNode){
22237 this.onNodeOut(this.lastOverNode, dd, e, data);
22238 this.lastOverNode = null;
22240 return this.onContainerOver(dd, e, data);
22242 if(this.lastOverNode != n){
22243 if(this.lastOverNode){
22244 this.onNodeOut(this.lastOverNode, dd, e, data);
22246 this.onNodeEnter(n, dd, e, data);
22247 this.lastOverNode = n;
22249 return this.onNodeOver(n, dd, e, data);
22253 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22254 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22255 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22256 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22257 * @param {Event} e The event
22258 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22260 notifyOut : function(dd, e, data){
22261 if(this.lastOverNode){
22262 this.onNodeOut(this.lastOverNode, dd, e, data);
22263 this.lastOverNode = null;
22268 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22269 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22270 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22271 * otherwise it will call {@link #onContainerDrop}.
22272 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22273 * @param {Event} e The event
22274 * @param {Object} data An object containing arbitrary data supplied by the drag source
22275 * @return {Boolean} True if the drop was valid, else false
22277 notifyDrop : function(dd, e, data){
22278 if(this.lastOverNode){
22279 this.onNodeOut(this.lastOverNode, dd, e, data);
22280 this.lastOverNode = null;
22282 var n = this.getTargetFromEvent(e);
22284 this.onNodeDrop(n, dd, e, data) :
22285 this.onContainerDrop(dd, e, data);
22289 triggerCacheRefresh : function(){
22290 Roo.dd.DDM.refreshCache(this.groups);
22294 * Ext JS Library 1.1.1
22295 * Copyright(c) 2006-2007, Ext JS, LLC.
22297 * Originally Released Under LGPL - original licence link has changed is not relivant.
22300 * <script type="text/javascript">
22306 * These classes are derivatives of the similarly named classes in the YUI Library.
22307 * The original license:
22308 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
22309 * Code licensed under the BSD License:
22310 * http://developer.yahoo.net/yui/license.txt
22315 var Event=Roo.EventManager;
22316 var Dom=Roo.lib.Dom;
22319 * @class Roo.dd.DragDrop
22320 * @extends Roo.util.Observable
22321 * Defines the interface and base operation of items that that can be
22322 * dragged or can be drop targets. It was designed to be extended, overriding
22323 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
22324 * Up to three html elements can be associated with a DragDrop instance:
22326 * <li>linked element: the element that is passed into the constructor.
22327 * This is the element which defines the boundaries for interaction with
22328 * other DragDrop objects.</li>
22329 * <li>handle element(s): The drag operation only occurs if the element that
22330 * was clicked matches a handle element. By default this is the linked
22331 * element, but there are times that you will want only a portion of the
22332 * linked element to initiate the drag operation, and the setHandleElId()
22333 * method provides a way to define this.</li>
22334 * <li>drag element: this represents the element that would be moved along
22335 * with the cursor during a drag operation. By default, this is the linked
22336 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
22337 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
22340 * This class should not be instantiated until the onload event to ensure that
22341 * the associated elements are available.
22342 * The following would define a DragDrop obj that would interact with any
22343 * other DragDrop obj in the "group1" group:
22345 * dd = new Roo.dd.DragDrop("div1", "group1");
22347 * Since none of the event handlers have been implemented, nothing would
22348 * actually happen if you were to run the code above. Normally you would
22349 * override this class or one of the default implementations, but you can
22350 * also override the methods you want on an instance of the class...
22352 * dd.onDragDrop = function(e, id) {
22353 * alert("dd was dropped on " + id);
22357 * @param {String} id of the element that is linked to this instance
22358 * @param {String} sGroup the group of related DragDrop objects
22359 * @param {object} config an object containing configurable attributes
22360 * Valid properties for DragDrop:
22361 * padding, isTarget, maintainOffset, primaryButtonOnly
22363 Roo.dd.DragDrop = function(id, sGroup, config) {
22365 this.init(id, sGroup, config);
22370 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
22373 * The id of the element associated with this object. This is what we
22374 * refer to as the "linked element" because the size and position of
22375 * this element is used to determine when the drag and drop objects have
22383 * Configuration attributes passed into the constructor
22390 * The id of the element that will be dragged. By default this is same
22391 * as the linked element , but could be changed to another element. Ex:
22393 * @property dragElId
22400 * the id of the element that initiates the drag operation. By default
22401 * this is the linked element, but could be changed to be a child of this
22402 * element. This lets us do things like only starting the drag when the
22403 * header element within the linked html element is clicked.
22404 * @property handleElId
22411 * An associative array of HTML tags that will be ignored if clicked.
22412 * @property invalidHandleTypes
22413 * @type {string: string}
22415 invalidHandleTypes: null,
22418 * An associative array of ids for elements that will be ignored if clicked
22419 * @property invalidHandleIds
22420 * @type {string: string}
22422 invalidHandleIds: null,
22425 * An indexted array of css class names for elements that will be ignored
22427 * @property invalidHandleClasses
22430 invalidHandleClasses: null,
22433 * The linked element's absolute X position at the time the drag was
22435 * @property startPageX
22442 * The linked element's absolute X position at the time the drag was
22444 * @property startPageY
22451 * The group defines a logical collection of DragDrop objects that are
22452 * related. Instances only get events when interacting with other
22453 * DragDrop object in the same group. This lets us define multiple
22454 * groups using a single DragDrop subclass if we want.
22456 * @type {string: string}
22461 * Individual drag/drop instances can be locked. This will prevent
22462 * onmousedown start drag.
22470 * Lock this instance
22473 lock: function() { this.locked = true; },
22476 * Unlock this instace
22479 unlock: function() { this.locked = false; },
22482 * By default, all insances can be a drop target. This can be disabled by
22483 * setting isTarget to false.
22490 * The padding configured for this drag and drop object for calculating
22491 * the drop zone intersection with this object.
22498 * Cached reference to the linked element
22499 * @property _domRef
22505 * Internal typeof flag
22506 * @property __ygDragDrop
22509 __ygDragDrop: true,
22512 * Set to true when horizontal contraints are applied
22513 * @property constrainX
22520 * Set to true when vertical contraints are applied
22521 * @property constrainY
22528 * The left constraint
22536 * The right constraint
22544 * The up constraint
22553 * The down constraint
22561 * Maintain offsets when we resetconstraints. Set to true when you want
22562 * the position of the element relative to its parent to stay the same
22563 * when the page changes
22565 * @property maintainOffset
22568 maintainOffset: false,
22571 * Array of pixel locations the element will snap to if we specified a
22572 * horizontal graduation/interval. This array is generated automatically
22573 * when you define a tick interval.
22580 * Array of pixel locations the element will snap to if we specified a
22581 * vertical graduation/interval. This array is generated automatically
22582 * when you define a tick interval.
22589 * By default the drag and drop instance will only respond to the primary
22590 * button click (left button for a right-handed mouse). Set to true to
22591 * allow drag and drop to start with any mouse click that is propogated
22593 * @property primaryButtonOnly
22596 primaryButtonOnly: true,
22599 * The availabe property is false until the linked dom element is accessible.
22600 * @property available
22606 * By default, drags can only be initiated if the mousedown occurs in the
22607 * region the linked element is. This is done in part to work around a
22608 * bug in some browsers that mis-report the mousedown if the previous
22609 * mouseup happened outside of the window. This property is set to true
22610 * if outer handles are defined.
22612 * @property hasOuterHandles
22616 hasOuterHandles: false,
22619 * Code that executes immediately before the startDrag event
22620 * @method b4StartDrag
22623 b4StartDrag: function(x, y) { },
22626 * Abstract method called after a drag/drop object is clicked
22627 * and the drag or mousedown time thresholds have beeen met.
22628 * @method startDrag
22629 * @param {int} X click location
22630 * @param {int} Y click location
22632 startDrag: function(x, y) { /* override this */ },
22635 * Code that executes immediately before the onDrag event
22639 b4Drag: function(e) { },
22642 * Abstract method called during the onMouseMove event while dragging an
22645 * @param {Event} e the mousemove event
22647 onDrag: function(e) { /* override this */ },
22650 * Abstract method called when this element fist begins hovering over
22651 * another DragDrop obj
22652 * @method onDragEnter
22653 * @param {Event} e the mousemove event
22654 * @param {String|DragDrop[]} id In POINT mode, the element
22655 * id this is hovering over. In INTERSECT mode, an array of one or more
22656 * dragdrop items being hovered over.
22658 onDragEnter: function(e, id) { /* override this */ },
22661 * Code that executes immediately before the onDragOver event
22662 * @method b4DragOver
22665 b4DragOver: function(e) { },
22668 * Abstract method called when this element is hovering over another
22670 * @method onDragOver
22671 * @param {Event} e the mousemove event
22672 * @param {String|DragDrop[]} id In POINT mode, the element
22673 * id this is hovering over. In INTERSECT mode, an array of dd items
22674 * being hovered over.
22676 onDragOver: function(e, id) { /* override this */ },
22679 * Code that executes immediately before the onDragOut event
22680 * @method b4DragOut
22683 b4DragOut: function(e) { },
22686 * Abstract method called when we are no longer hovering over an element
22687 * @method onDragOut
22688 * @param {Event} e the mousemove event
22689 * @param {String|DragDrop[]} id In POINT mode, the element
22690 * id this was hovering over. In INTERSECT mode, an array of dd items
22691 * that the mouse is no longer over.
22693 onDragOut: function(e, id) { /* override this */ },
22696 * Code that executes immediately before the onDragDrop event
22697 * @method b4DragDrop
22700 b4DragDrop: function(e) { },
22703 * Abstract method called when this item is dropped on another DragDrop
22705 * @method onDragDrop
22706 * @param {Event} e the mouseup event
22707 * @param {String|DragDrop[]} id In POINT mode, the element
22708 * id this was dropped on. In INTERSECT mode, an array of dd items this
22711 onDragDrop: function(e, id) { /* override this */ },
22714 * Abstract method called when this item is dropped on an area with no
22716 * @method onInvalidDrop
22717 * @param {Event} e the mouseup event
22719 onInvalidDrop: function(e) { /* override this */ },
22722 * Code that executes immediately before the endDrag event
22723 * @method b4EndDrag
22726 b4EndDrag: function(e) { },
22729 * Fired when we are done dragging the object
22731 * @param {Event} e the mouseup event
22733 endDrag: function(e) { /* override this */ },
22736 * Code executed immediately before the onMouseDown event
22737 * @method b4MouseDown
22738 * @param {Event} e the mousedown event
22741 b4MouseDown: function(e) { },
22744 * Event handler that fires when a drag/drop obj gets a mousedown
22745 * @method onMouseDown
22746 * @param {Event} e the mousedown event
22748 onMouseDown: function(e) { /* override this */ },
22751 * Event handler that fires when a drag/drop obj gets a mouseup
22752 * @method onMouseUp
22753 * @param {Event} e the mouseup event
22755 onMouseUp: function(e) { /* override this */ },
22758 * Override the onAvailable method to do what is needed after the initial
22759 * position was determined.
22760 * @method onAvailable
22762 onAvailable: function () {
22766 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
22769 defaultPadding : {left:0, right:0, top:0, bottom:0},
22772 * Initializes the drag drop object's constraints to restrict movement to a certain element.
22776 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
22777 { dragElId: "existingProxyDiv" });
22778 dd.startDrag = function(){
22779 this.constrainTo("parent-id");
22782 * Or you can initalize it using the {@link Roo.Element} object:
22784 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
22785 startDrag : function(){
22786 this.constrainTo("parent-id");
22790 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
22791 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
22792 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
22793 * an object containing the sides to pad. For example: {right:10, bottom:10}
22794 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
22796 constrainTo : function(constrainTo, pad, inContent){
22797 if(typeof pad == "number"){
22798 pad = {left: pad, right:pad, top:pad, bottom:pad};
22800 pad = pad || this.defaultPadding;
22801 var b = Roo.get(this.getEl()).getBox();
22802 var ce = Roo.get(constrainTo);
22803 var s = ce.getScroll();
22804 var c, cd = ce.dom;
22805 if(cd == document.body){
22806 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
22809 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
22813 var topSpace = b.y - c.y;
22814 var leftSpace = b.x - c.x;
22816 this.resetConstraints();
22817 this.setXConstraint(leftSpace - (pad.left||0), // left
22818 c.width - leftSpace - b.width - (pad.right||0) //right
22820 this.setYConstraint(topSpace - (pad.top||0), //top
22821 c.height - topSpace - b.height - (pad.bottom||0) //bottom
22826 * Returns a reference to the linked element
22828 * @return {HTMLElement} the html element
22830 getEl: function() {
22831 if (!this._domRef) {
22832 this._domRef = Roo.getDom(this.id);
22835 return this._domRef;
22839 * Returns a reference to the actual element to drag. By default this is
22840 * the same as the html element, but it can be assigned to another
22841 * element. An example of this can be found in Roo.dd.DDProxy
22842 * @method getDragEl
22843 * @return {HTMLElement} the html element
22845 getDragEl: function() {
22846 return Roo.getDom(this.dragElId);
22850 * Sets up the DragDrop object. Must be called in the constructor of any
22851 * Roo.dd.DragDrop subclass
22853 * @param id the id of the linked element
22854 * @param {String} sGroup the group of related items
22855 * @param {object} config configuration attributes
22857 init: function(id, sGroup, config) {
22858 this.initTarget(id, sGroup, config);
22859 if (!Roo.isTouch) {
22860 Event.on(this.id, "mousedown", this.handleMouseDown, this);
22862 Event.on(this.id, "touchstart", this.handleMouseDown, this);
22863 // Event.on(this.id, "selectstart", Event.preventDefault);
22867 * Initializes Targeting functionality only... the object does not
22868 * get a mousedown handler.
22869 * @method initTarget
22870 * @param id the id of the linked element
22871 * @param {String} sGroup the group of related items
22872 * @param {object} config configuration attributes
22874 initTarget: function(id, sGroup, config) {
22876 // configuration attributes
22877 this.config = config || {};
22879 // create a local reference to the drag and drop manager
22880 this.DDM = Roo.dd.DDM;
22881 // initialize the groups array
22884 // assume that we have an element reference instead of an id if the
22885 // parameter is not a string
22886 if (typeof id !== "string") {
22893 // add to an interaction group
22894 this.addToGroup((sGroup) ? sGroup : "default");
22896 // We don't want to register this as the handle with the manager
22897 // so we just set the id rather than calling the setter.
22898 this.handleElId = id;
22900 // the linked element is the element that gets dragged by default
22901 this.setDragElId(id);
22903 // by default, clicked anchors will not start drag operations.
22904 this.invalidHandleTypes = { A: "A" };
22905 this.invalidHandleIds = {};
22906 this.invalidHandleClasses = [];
22908 this.applyConfig();
22910 this.handleOnAvailable();
22914 * Applies the configuration parameters that were passed into the constructor.
22915 * This is supposed to happen at each level through the inheritance chain. So
22916 * a DDProxy implentation will execute apply config on DDProxy, DD, and
22917 * DragDrop in order to get all of the parameters that are available in
22919 * @method applyConfig
22921 applyConfig: function() {
22923 // configurable properties:
22924 // padding, isTarget, maintainOffset, primaryButtonOnly
22925 this.padding = this.config.padding || [0, 0, 0, 0];
22926 this.isTarget = (this.config.isTarget !== false);
22927 this.maintainOffset = (this.config.maintainOffset);
22928 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
22933 * Executed when the linked element is available
22934 * @method handleOnAvailable
22937 handleOnAvailable: function() {
22938 this.available = true;
22939 this.resetConstraints();
22940 this.onAvailable();
22944 * Configures the padding for the target zone in px. Effectively expands
22945 * (or reduces) the virtual object size for targeting calculations.
22946 * Supports css-style shorthand; if only one parameter is passed, all sides
22947 * will have that padding, and if only two are passed, the top and bottom
22948 * will have the first param, the left and right the second.
22949 * @method setPadding
22950 * @param {int} iTop Top pad
22951 * @param {int} iRight Right pad
22952 * @param {int} iBot Bot pad
22953 * @param {int} iLeft Left pad
22955 setPadding: function(iTop, iRight, iBot, iLeft) {
22956 // this.padding = [iLeft, iRight, iTop, iBot];
22957 if (!iRight && 0 !== iRight) {
22958 this.padding = [iTop, iTop, iTop, iTop];
22959 } else if (!iBot && 0 !== iBot) {
22960 this.padding = [iTop, iRight, iTop, iRight];
22962 this.padding = [iTop, iRight, iBot, iLeft];
22967 * Stores the initial placement of the linked element.
22968 * @method setInitialPosition
22969 * @param {int} diffX the X offset, default 0
22970 * @param {int} diffY the Y offset, default 0
22972 setInitPosition: function(diffX, diffY) {
22973 var el = this.getEl();
22975 if (!this.DDM.verifyEl(el)) {
22979 var dx = diffX || 0;
22980 var dy = diffY || 0;
22982 var p = Dom.getXY( el );
22984 this.initPageX = p[0] - dx;
22985 this.initPageY = p[1] - dy;
22987 this.lastPageX = p[0];
22988 this.lastPageY = p[1];
22991 this.setStartPosition(p);
22995 * Sets the start position of the element. This is set when the obj
22996 * is initialized, the reset when a drag is started.
22997 * @method setStartPosition
22998 * @param pos current position (from previous lookup)
23001 setStartPosition: function(pos) {
23002 var p = pos || Dom.getXY( this.getEl() );
23003 this.deltaSetXY = null;
23005 this.startPageX = p[0];
23006 this.startPageY = p[1];
23010 * Add this instance to a group of related drag/drop objects. All
23011 * instances belong to at least one group, and can belong to as many
23012 * groups as needed.
23013 * @method addToGroup
23014 * @param sGroup {string} the name of the group
23016 addToGroup: function(sGroup) {
23017 this.groups[sGroup] = true;
23018 this.DDM.regDragDrop(this, sGroup);
23022 * Remove's this instance from the supplied interaction group
23023 * @method removeFromGroup
23024 * @param {string} sGroup The group to drop
23026 removeFromGroup: function(sGroup) {
23027 if (this.groups[sGroup]) {
23028 delete this.groups[sGroup];
23031 this.DDM.removeDDFromGroup(this, sGroup);
23035 * Allows you to specify that an element other than the linked element
23036 * will be moved with the cursor during a drag
23037 * @method setDragElId
23038 * @param id {string} the id of the element that will be used to initiate the drag
23040 setDragElId: function(id) {
23041 this.dragElId = id;
23045 * Allows you to specify a child of the linked element that should be
23046 * used to initiate the drag operation. An example of this would be if
23047 * you have a content div with text and links. Clicking anywhere in the
23048 * content area would normally start the drag operation. Use this method
23049 * to specify that an element inside of the content div is the element
23050 * that starts the drag operation.
23051 * @method setHandleElId
23052 * @param id {string} the id of the element that will be used to
23053 * initiate the drag.
23055 setHandleElId: function(id) {
23056 if (typeof id !== "string") {
23059 this.handleElId = id;
23060 this.DDM.regHandle(this.id, id);
23064 * Allows you to set an element outside of the linked element as a drag
23066 * @method setOuterHandleElId
23067 * @param id the id of the element that will be used to initiate the drag
23069 setOuterHandleElId: function(id) {
23070 if (typeof id !== "string") {
23073 Event.on(id, "mousedown",
23074 this.handleMouseDown, this);
23075 this.setHandleElId(id);
23077 this.hasOuterHandles = true;
23081 * Remove all drag and drop hooks for this element
23084 unreg: function() {
23085 Event.un(this.id, "mousedown",
23086 this.handleMouseDown);
23087 Event.un(this.id, "touchstart",
23088 this.handleMouseDown);
23089 this._domRef = null;
23090 this.DDM._remove(this);
23093 destroy : function(){
23098 * Returns true if this instance is locked, or the drag drop mgr is locked
23099 * (meaning that all drag/drop is disabled on the page.)
23101 * @return {boolean} true if this obj or all drag/drop is locked, else
23104 isLocked: function() {
23105 return (this.DDM.isLocked() || this.locked);
23109 * Fired when this object is clicked
23110 * @method handleMouseDown
23112 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
23115 handleMouseDown: function(e, oDD){
23117 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
23118 //Roo.log('not touch/ button !=0');
23121 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
23122 return; // double touch..
23126 if (this.isLocked()) {
23127 //Roo.log('locked');
23131 this.DDM.refreshCache(this.groups);
23132 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
23133 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
23134 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
23135 //Roo.log('no outer handes or not over target');
23138 // Roo.log('check validator');
23139 if (this.clickValidator(e)) {
23140 // Roo.log('validate success');
23141 // set the initial element position
23142 this.setStartPosition();
23145 this.b4MouseDown(e);
23146 this.onMouseDown(e);
23148 this.DDM.handleMouseDown(e, this);
23150 this.DDM.stopEvent(e);
23158 clickValidator: function(e) {
23159 var target = e.getTarget();
23160 return ( this.isValidHandleChild(target) &&
23161 (this.id == this.handleElId ||
23162 this.DDM.handleWasClicked(target, this.id)) );
23166 * Allows you to specify a tag name that should not start a drag operation
23167 * when clicked. This is designed to facilitate embedding links within a
23168 * drag handle that do something other than start the drag.
23169 * @method addInvalidHandleType
23170 * @param {string} tagName the type of element to exclude
23172 addInvalidHandleType: function(tagName) {
23173 var type = tagName.toUpperCase();
23174 this.invalidHandleTypes[type] = type;
23178 * Lets you to specify an element id for a child of a drag handle
23179 * that should not initiate a drag
23180 * @method addInvalidHandleId
23181 * @param {string} id the element id of the element you wish to ignore
23183 addInvalidHandleId: function(id) {
23184 if (typeof id !== "string") {
23187 this.invalidHandleIds[id] = id;
23191 * Lets you specify a css class of elements that will not initiate a drag
23192 * @method addInvalidHandleClass
23193 * @param {string} cssClass the class of the elements you wish to ignore
23195 addInvalidHandleClass: function(cssClass) {
23196 this.invalidHandleClasses.push(cssClass);
23200 * Unsets an excluded tag name set by addInvalidHandleType
23201 * @method removeInvalidHandleType
23202 * @param {string} tagName the type of element to unexclude
23204 removeInvalidHandleType: function(tagName) {
23205 var type = tagName.toUpperCase();
23206 // this.invalidHandleTypes[type] = null;
23207 delete this.invalidHandleTypes[type];
23211 * Unsets an invalid handle id
23212 * @method removeInvalidHandleId
23213 * @param {string} id the id of the element to re-enable
23215 removeInvalidHandleId: function(id) {
23216 if (typeof id !== "string") {
23219 delete this.invalidHandleIds[id];
23223 * Unsets an invalid css class
23224 * @method removeInvalidHandleClass
23225 * @param {string} cssClass the class of the element(s) you wish to
23228 removeInvalidHandleClass: function(cssClass) {
23229 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
23230 if (this.invalidHandleClasses[i] == cssClass) {
23231 delete this.invalidHandleClasses[i];
23237 * Checks the tag exclusion list to see if this click should be ignored
23238 * @method isValidHandleChild
23239 * @param {HTMLElement} node the HTMLElement to evaluate
23240 * @return {boolean} true if this is a valid tag type, false if not
23242 isValidHandleChild: function(node) {
23245 // var n = (node.nodeName == "#text") ? node.parentNode : node;
23248 nodeName = node.nodeName.toUpperCase();
23250 nodeName = node.nodeName;
23252 valid = valid && !this.invalidHandleTypes[nodeName];
23253 valid = valid && !this.invalidHandleIds[node.id];
23255 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
23256 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
23265 * Create the array of horizontal tick marks if an interval was specified
23266 * in setXConstraint().
23267 * @method setXTicks
23270 setXTicks: function(iStartX, iTickSize) {
23272 this.xTickSize = iTickSize;
23276 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
23278 this.xTicks[this.xTicks.length] = i;
23283 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
23285 this.xTicks[this.xTicks.length] = i;
23290 this.xTicks.sort(this.DDM.numericSort) ;
23294 * Create the array of vertical tick marks if an interval was specified in
23295 * setYConstraint().
23296 * @method setYTicks
23299 setYTicks: function(iStartY, iTickSize) {
23301 this.yTickSize = iTickSize;
23305 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
23307 this.yTicks[this.yTicks.length] = i;
23312 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
23314 this.yTicks[this.yTicks.length] = i;
23319 this.yTicks.sort(this.DDM.numericSort) ;
23323 * By default, the element can be dragged any place on the screen. Use
23324 * this method to limit the horizontal travel of the element. Pass in
23325 * 0,0 for the parameters if you want to lock the drag to the y axis.
23326 * @method setXConstraint
23327 * @param {int} iLeft the number of pixels the element can move to the left
23328 * @param {int} iRight the number of pixels the element can move to the
23330 * @param {int} iTickSize optional parameter for specifying that the
23332 * should move iTickSize pixels at a time.
23334 setXConstraint: function(iLeft, iRight, iTickSize) {
23335 this.leftConstraint = iLeft;
23336 this.rightConstraint = iRight;
23338 this.minX = this.initPageX - iLeft;
23339 this.maxX = this.initPageX + iRight;
23340 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
23342 this.constrainX = true;
23346 * Clears any constraints applied to this instance. Also clears ticks
23347 * since they can't exist independent of a constraint at this time.
23348 * @method clearConstraints
23350 clearConstraints: function() {
23351 this.constrainX = false;
23352 this.constrainY = false;
23357 * Clears any tick interval defined for this instance
23358 * @method clearTicks
23360 clearTicks: function() {
23361 this.xTicks = null;
23362 this.yTicks = null;
23363 this.xTickSize = 0;
23364 this.yTickSize = 0;
23368 * By default, the element can be dragged any place on the screen. Set
23369 * this to limit the vertical travel of the element. Pass in 0,0 for the
23370 * parameters if you want to lock the drag to the x axis.
23371 * @method setYConstraint
23372 * @param {int} iUp the number of pixels the element can move up
23373 * @param {int} iDown the number of pixels the element can move down
23374 * @param {int} iTickSize optional parameter for specifying that the
23375 * element should move iTickSize pixels at a time.
23377 setYConstraint: function(iUp, iDown, iTickSize) {
23378 this.topConstraint = iUp;
23379 this.bottomConstraint = iDown;
23381 this.minY = this.initPageY - iUp;
23382 this.maxY = this.initPageY + iDown;
23383 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
23385 this.constrainY = true;
23390 * resetConstraints must be called if you manually reposition a dd element.
23391 * @method resetConstraints
23392 * @param {boolean} maintainOffset
23394 resetConstraints: function() {
23397 // Maintain offsets if necessary
23398 if (this.initPageX || this.initPageX === 0) {
23399 // figure out how much this thing has moved
23400 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
23401 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
23403 this.setInitPosition(dx, dy);
23405 // This is the first time we have detected the element's position
23407 this.setInitPosition();
23410 if (this.constrainX) {
23411 this.setXConstraint( this.leftConstraint,
23412 this.rightConstraint,
23416 if (this.constrainY) {
23417 this.setYConstraint( this.topConstraint,
23418 this.bottomConstraint,
23424 * Normally the drag element is moved pixel by pixel, but we can specify
23425 * that it move a number of pixels at a time. This method resolves the
23426 * location when we have it set up like this.
23428 * @param {int} val where we want to place the object
23429 * @param {int[]} tickArray sorted array of valid points
23430 * @return {int} the closest tick
23433 getTick: function(val, tickArray) {
23436 // If tick interval is not defined, it is effectively 1 pixel,
23437 // so we return the value passed to us.
23439 } else if (tickArray[0] >= val) {
23440 // The value is lower than the first tick, so we return the first
23442 return tickArray[0];
23444 for (var i=0, len=tickArray.length; i<len; ++i) {
23446 if (tickArray[next] && tickArray[next] >= val) {
23447 var diff1 = val - tickArray[i];
23448 var diff2 = tickArray[next] - val;
23449 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
23453 // The value is larger than the last tick, so we return the last
23455 return tickArray[tickArray.length - 1];
23462 * @return {string} string representation of the dd obj
23464 toString: function() {
23465 return ("DragDrop " + this.id);
23473 * Ext JS Library 1.1.1
23474 * Copyright(c) 2006-2007, Ext JS, LLC.
23476 * Originally Released Under LGPL - original licence link has changed is not relivant.
23479 * <script type="text/javascript">
23484 * The drag and drop utility provides a framework for building drag and drop
23485 * applications. In addition to enabling drag and drop for specific elements,
23486 * the drag and drop elements are tracked by the manager class, and the
23487 * interactions between the various elements are tracked during the drag and
23488 * the implementing code is notified about these important moments.
23491 // Only load the library once. Rewriting the manager class would orphan
23492 // existing drag and drop instances.
23493 if (!Roo.dd.DragDropMgr) {
23496 * @class Roo.dd.DragDropMgr
23497 * DragDropMgr is a singleton that tracks the element interaction for
23498 * all DragDrop items in the window. Generally, you will not call
23499 * this class directly, but it does have helper methods that could
23500 * be useful in your DragDrop implementations.
23503 Roo.dd.DragDropMgr = function() {
23505 var Event = Roo.EventManager;
23510 * Two dimensional Array of registered DragDrop objects. The first
23511 * dimension is the DragDrop item group, the second the DragDrop
23514 * @type {string: string}
23521 * Array of element ids defined as drag handles. Used to determine
23522 * if the element that generated the mousedown event is actually the
23523 * handle and not the html element itself.
23524 * @property handleIds
23525 * @type {string: string}
23532 * the DragDrop object that is currently being dragged
23533 * @property dragCurrent
23541 * the DragDrop object(s) that are being hovered over
23542 * @property dragOvers
23550 * the X distance between the cursor and the object being dragged
23559 * the Y distance between the cursor and the object being dragged
23568 * Flag to determine if we should prevent the default behavior of the
23569 * events we define. By default this is true, but this can be set to
23570 * false if you need the default behavior (not recommended)
23571 * @property preventDefault
23575 preventDefault: true,
23578 * Flag to determine if we should stop the propagation of the events
23579 * we generate. This is true by default but you may want to set it to
23580 * false if the html element contains other features that require the
23582 * @property stopPropagation
23586 stopPropagation: true,
23589 * Internal flag that is set to true when drag and drop has been
23591 * @property initialized
23598 * All drag and drop can be disabled.
23606 * Called the first time an element is registered.
23612 this.initialized = true;
23616 * In point mode, drag and drop interaction is defined by the
23617 * location of the cursor during the drag/drop
23625 * In intersect mode, drag and drop interactio nis defined by the
23626 * overlap of two or more drag and drop objects.
23627 * @property INTERSECT
23634 * The current drag and drop mode. Default: POINT
23642 * Runs method on all drag and drop objects
23643 * @method _execOnAll
23647 _execOnAll: function(sMethod, args) {
23648 for (var i in this.ids) {
23649 for (var j in this.ids[i]) {
23650 var oDD = this.ids[i][j];
23651 if (! this.isTypeOfDD(oDD)) {
23654 oDD[sMethod].apply(oDD, args);
23660 * Drag and drop initialization. Sets up the global event handlers
23665 _onLoad: function() {
23669 if (!Roo.isTouch) {
23670 Event.on(document, "mouseup", this.handleMouseUp, this, true);
23671 Event.on(document, "mousemove", this.handleMouseMove, this, true);
23673 Event.on(document, "touchend", this.handleMouseUp, this, true);
23674 Event.on(document, "touchmove", this.handleMouseMove, this, true);
23676 Event.on(window, "unload", this._onUnload, this, true);
23677 Event.on(window, "resize", this._onResize, this, true);
23678 // Event.on(window, "mouseout", this._test);
23683 * Reset constraints on all drag and drop objs
23684 * @method _onResize
23688 _onResize: function(e) {
23689 this._execOnAll("resetConstraints", []);
23693 * Lock all drag and drop functionality
23697 lock: function() { this.locked = true; },
23700 * Unlock all drag and drop functionality
23704 unlock: function() { this.locked = false; },
23707 * Is drag and drop locked?
23709 * @return {boolean} True if drag and drop is locked, false otherwise.
23712 isLocked: function() { return this.locked; },
23715 * Location cache that is set for all drag drop objects when a drag is
23716 * initiated, cleared when the drag is finished.
23717 * @property locationCache
23724 * Set useCache to false if you want to force object the lookup of each
23725 * drag and drop linked element constantly during a drag.
23726 * @property useCache
23733 * The number of pixels that the mouse needs to move after the
23734 * mousedown before the drag is initiated. Default=3;
23735 * @property clickPixelThresh
23739 clickPixelThresh: 3,
23742 * The number of milliseconds after the mousedown event to initiate the
23743 * drag if we don't get a mouseup event. Default=1000
23744 * @property clickTimeThresh
23748 clickTimeThresh: 350,
23751 * Flag that indicates that either the drag pixel threshold or the
23752 * mousdown time threshold has been met
23753 * @property dragThreshMet
23758 dragThreshMet: false,
23761 * Timeout used for the click time threshold
23762 * @property clickTimeout
23767 clickTimeout: null,
23770 * The X position of the mousedown event stored for later use when a
23771 * drag threshold is met.
23780 * The Y position of the mousedown event stored for later use when a
23781 * drag threshold is met.
23790 * Each DragDrop instance must be registered with the DragDropMgr.
23791 * This is executed in DragDrop.init()
23792 * @method regDragDrop
23793 * @param {DragDrop} oDD the DragDrop object to register
23794 * @param {String} sGroup the name of the group this element belongs to
23797 regDragDrop: function(oDD, sGroup) {
23798 if (!this.initialized) { this.init(); }
23800 if (!this.ids[sGroup]) {
23801 this.ids[sGroup] = {};
23803 this.ids[sGroup][oDD.id] = oDD;
23807 * Removes the supplied dd instance from the supplied group. Executed
23808 * by DragDrop.removeFromGroup, so don't call this function directly.
23809 * @method removeDDFromGroup
23813 removeDDFromGroup: function(oDD, sGroup) {
23814 if (!this.ids[sGroup]) {
23815 this.ids[sGroup] = {};
23818 var obj = this.ids[sGroup];
23819 if (obj && obj[oDD.id]) {
23820 delete obj[oDD.id];
23825 * Unregisters a drag and drop item. This is executed in
23826 * DragDrop.unreg, use that method instead of calling this directly.
23831 _remove: function(oDD) {
23832 for (var g in oDD.groups) {
23833 if (g && this.ids[g][oDD.id]) {
23834 delete this.ids[g][oDD.id];
23837 delete this.handleIds[oDD.id];
23841 * Each DragDrop handle element must be registered. This is done
23842 * automatically when executing DragDrop.setHandleElId()
23843 * @method regHandle
23844 * @param {String} sDDId the DragDrop id this element is a handle for
23845 * @param {String} sHandleId the id of the element that is the drag
23849 regHandle: function(sDDId, sHandleId) {
23850 if (!this.handleIds[sDDId]) {
23851 this.handleIds[sDDId] = {};
23853 this.handleIds[sDDId][sHandleId] = sHandleId;
23857 * Utility function to determine if a given element has been
23858 * registered as a drag drop item.
23859 * @method isDragDrop
23860 * @param {String} id the element id to check
23861 * @return {boolean} true if this element is a DragDrop item,
23865 isDragDrop: function(id) {
23866 return ( this.getDDById(id) ) ? true : false;
23870 * Returns the drag and drop instances that are in all groups the
23871 * passed in instance belongs to.
23872 * @method getRelated
23873 * @param {DragDrop} p_oDD the obj to get related data for
23874 * @param {boolean} bTargetsOnly if true, only return targetable objs
23875 * @return {DragDrop[]} the related instances
23878 getRelated: function(p_oDD, bTargetsOnly) {
23880 for (var i in p_oDD.groups) {
23881 for (j in this.ids[i]) {
23882 var dd = this.ids[i][j];
23883 if (! this.isTypeOfDD(dd)) {
23886 if (!bTargetsOnly || dd.isTarget) {
23887 oDDs[oDDs.length] = dd;
23896 * Returns true if the specified dd target is a legal target for
23897 * the specifice drag obj
23898 * @method isLegalTarget
23899 * @param {DragDrop} the drag obj
23900 * @param {DragDrop} the target
23901 * @return {boolean} true if the target is a legal target for the
23905 isLegalTarget: function (oDD, oTargetDD) {
23906 var targets = this.getRelated(oDD, true);
23907 for (var i=0, len=targets.length;i<len;++i) {
23908 if (targets[i].id == oTargetDD.id) {
23917 * My goal is to be able to transparently determine if an object is
23918 * typeof DragDrop, and the exact subclass of DragDrop. typeof
23919 * returns "object", oDD.constructor.toString() always returns
23920 * "DragDrop" and not the name of the subclass. So for now it just
23921 * evaluates a well-known variable in DragDrop.
23922 * @method isTypeOfDD
23923 * @param {Object} the object to evaluate
23924 * @return {boolean} true if typeof oDD = DragDrop
23927 isTypeOfDD: function (oDD) {
23928 return (oDD && oDD.__ygDragDrop);
23932 * Utility function to determine if a given element has been
23933 * registered as a drag drop handle for the given Drag Drop object.
23935 * @param {String} id the element id to check
23936 * @return {boolean} true if this element is a DragDrop handle, false
23940 isHandle: function(sDDId, sHandleId) {
23941 return ( this.handleIds[sDDId] &&
23942 this.handleIds[sDDId][sHandleId] );
23946 * Returns the DragDrop instance for a given id
23947 * @method getDDById
23948 * @param {String} id the id of the DragDrop object
23949 * @return {DragDrop} the drag drop object, null if it is not found
23952 getDDById: function(id) {
23953 for (var i in this.ids) {
23954 if (this.ids[i][id]) {
23955 return this.ids[i][id];
23962 * Fired after a registered DragDrop object gets the mousedown event.
23963 * Sets up the events required to track the object being dragged
23964 * @method handleMouseDown
23965 * @param {Event} e the event
23966 * @param oDD the DragDrop object being dragged
23970 handleMouseDown: function(e, oDD) {
23972 Roo.QuickTips.disable();
23974 this.currentTarget = e.getTarget();
23976 this.dragCurrent = oDD;
23978 var el = oDD.getEl();
23980 // track start position
23981 this.startX = e.getPageX();
23982 this.startY = e.getPageY();
23984 this.deltaX = this.startX - el.offsetLeft;
23985 this.deltaY = this.startY - el.offsetTop;
23987 this.dragThreshMet = false;
23989 this.clickTimeout = setTimeout(
23991 var DDM = Roo.dd.DDM;
23992 DDM.startDrag(DDM.startX, DDM.startY);
23994 this.clickTimeThresh );
23998 * Fired when either the drag pixel threshol or the mousedown hold
23999 * time threshold has been met.
24000 * @method startDrag
24001 * @param x {int} the X position of the original mousedown
24002 * @param y {int} the Y position of the original mousedown
24005 startDrag: function(x, y) {
24006 clearTimeout(this.clickTimeout);
24007 if (this.dragCurrent) {
24008 this.dragCurrent.b4StartDrag(x, y);
24009 this.dragCurrent.startDrag(x, y);
24011 this.dragThreshMet = true;
24015 * Internal function to handle the mouseup event. Will be invoked
24016 * from the context of the document.
24017 * @method handleMouseUp
24018 * @param {Event} e the event
24022 handleMouseUp: function(e) {
24025 Roo.QuickTips.enable();
24027 if (! this.dragCurrent) {
24031 clearTimeout(this.clickTimeout);
24033 if (this.dragThreshMet) {
24034 this.fireEvents(e, true);
24044 * Utility to stop event propagation and event default, if these
24045 * features are turned on.
24046 * @method stopEvent
24047 * @param {Event} e the event as returned by this.getEvent()
24050 stopEvent: function(e){
24051 if(this.stopPropagation) {
24052 e.stopPropagation();
24055 if (this.preventDefault) {
24056 e.preventDefault();
24061 * Internal function to clean up event handlers after the drag
24062 * operation is complete
24064 * @param {Event} e the event
24068 stopDrag: function(e) {
24069 // Fire the drag end event for the item that was dragged
24070 if (this.dragCurrent) {
24071 if (this.dragThreshMet) {
24072 this.dragCurrent.b4EndDrag(e);
24073 this.dragCurrent.endDrag(e);
24076 this.dragCurrent.onMouseUp(e);
24079 this.dragCurrent = null;
24080 this.dragOvers = {};
24084 * Internal function to handle the mousemove event. Will be invoked
24085 * from the context of the html element.
24087 * @TODO figure out what we can do about mouse events lost when the
24088 * user drags objects beyond the window boundary. Currently we can
24089 * detect this in internet explorer by verifying that the mouse is
24090 * down during the mousemove event. Firefox doesn't give us the
24091 * button state on the mousemove event.
24092 * @method handleMouseMove
24093 * @param {Event} e the event
24097 handleMouseMove: function(e) {
24098 if (! this.dragCurrent) {
24102 // var button = e.which || e.button;
24104 // check for IE mouseup outside of page boundary
24105 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
24107 return this.handleMouseUp(e);
24110 if (!this.dragThreshMet) {
24111 var diffX = Math.abs(this.startX - e.getPageX());
24112 var diffY = Math.abs(this.startY - e.getPageY());
24113 if (diffX > this.clickPixelThresh ||
24114 diffY > this.clickPixelThresh) {
24115 this.startDrag(this.startX, this.startY);
24119 if (this.dragThreshMet) {
24120 this.dragCurrent.b4Drag(e);
24121 this.dragCurrent.onDrag(e);
24122 if(!this.dragCurrent.moveOnly){
24123 this.fireEvents(e, false);
24133 * Iterates over all of the DragDrop elements to find ones we are
24134 * hovering over or dropping on
24135 * @method fireEvents
24136 * @param {Event} e the event
24137 * @param {boolean} isDrop is this a drop op or a mouseover op?
24141 fireEvents: function(e, isDrop) {
24142 var dc = this.dragCurrent;
24144 // If the user did the mouse up outside of the window, we could
24145 // get here even though we have ended the drag.
24146 if (!dc || dc.isLocked()) {
24150 var pt = e.getPoint();
24152 // cache the previous dragOver array
24158 var enterEvts = [];
24160 // Check to see if the object(s) we were hovering over is no longer
24161 // being hovered over so we can fire the onDragOut event
24162 for (var i in this.dragOvers) {
24164 var ddo = this.dragOvers[i];
24166 if (! this.isTypeOfDD(ddo)) {
24170 if (! this.isOverTarget(pt, ddo, this.mode)) {
24171 outEvts.push( ddo );
24174 oldOvers[i] = true;
24175 delete this.dragOvers[i];
24178 for (var sGroup in dc.groups) {
24180 if ("string" != typeof sGroup) {
24184 for (i in this.ids[sGroup]) {
24185 var oDD = this.ids[sGroup][i];
24186 if (! this.isTypeOfDD(oDD)) {
24190 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
24191 if (this.isOverTarget(pt, oDD, this.mode)) {
24192 // look for drop interactions
24194 dropEvts.push( oDD );
24195 // look for drag enter and drag over interactions
24198 // initial drag over: dragEnter fires
24199 if (!oldOvers[oDD.id]) {
24200 enterEvts.push( oDD );
24201 // subsequent drag overs: dragOver fires
24203 overEvts.push( oDD );
24206 this.dragOvers[oDD.id] = oDD;
24214 if (outEvts.length) {
24215 dc.b4DragOut(e, outEvts);
24216 dc.onDragOut(e, outEvts);
24219 if (enterEvts.length) {
24220 dc.onDragEnter(e, enterEvts);
24223 if (overEvts.length) {
24224 dc.b4DragOver(e, overEvts);
24225 dc.onDragOver(e, overEvts);
24228 if (dropEvts.length) {
24229 dc.b4DragDrop(e, dropEvts);
24230 dc.onDragDrop(e, dropEvts);
24234 // fire dragout events
24236 for (i=0, len=outEvts.length; i<len; ++i) {
24237 dc.b4DragOut(e, outEvts[i].id);
24238 dc.onDragOut(e, outEvts[i].id);
24241 // fire enter events
24242 for (i=0,len=enterEvts.length; i<len; ++i) {
24243 // dc.b4DragEnter(e, oDD.id);
24244 dc.onDragEnter(e, enterEvts[i].id);
24247 // fire over events
24248 for (i=0,len=overEvts.length; i<len; ++i) {
24249 dc.b4DragOver(e, overEvts[i].id);
24250 dc.onDragOver(e, overEvts[i].id);
24253 // fire drop events
24254 for (i=0, len=dropEvts.length; i<len; ++i) {
24255 dc.b4DragDrop(e, dropEvts[i].id);
24256 dc.onDragDrop(e, dropEvts[i].id);
24261 // notify about a drop that did not find a target
24262 if (isDrop && !dropEvts.length) {
24263 dc.onInvalidDrop(e);
24269 * Helper function for getting the best match from the list of drag
24270 * and drop objects returned by the drag and drop events when we are
24271 * in INTERSECT mode. It returns either the first object that the
24272 * cursor is over, or the object that has the greatest overlap with
24273 * the dragged element.
24274 * @method getBestMatch
24275 * @param {DragDrop[]} dds The array of drag and drop objects
24277 * @return {DragDrop} The best single match
24280 getBestMatch: function(dds) {
24282 // Return null if the input is not what we expect
24283 //if (!dds || !dds.length || dds.length == 0) {
24285 // If there is only one item, it wins
24286 //} else if (dds.length == 1) {
24288 var len = dds.length;
24293 // Loop through the targeted items
24294 for (var i=0; i<len; ++i) {
24296 // If the cursor is over the object, it wins. If the
24297 // cursor is over multiple matches, the first one we come
24299 if (dd.cursorIsOver) {
24302 // Otherwise the object with the most overlap wins
24305 winner.overlap.getArea() < dd.overlap.getArea()) {
24316 * Refreshes the cache of the top-left and bottom-right points of the
24317 * drag and drop objects in the specified group(s). This is in the
24318 * format that is stored in the drag and drop instance, so typical
24321 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
24325 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
24327 * @TODO this really should be an indexed array. Alternatively this
24328 * method could accept both.
24329 * @method refreshCache
24330 * @param {Object} groups an associative array of groups to refresh
24333 refreshCache: function(groups) {
24334 for (var sGroup in groups) {
24335 if ("string" != typeof sGroup) {
24338 for (var i in this.ids[sGroup]) {
24339 var oDD = this.ids[sGroup][i];
24341 if (this.isTypeOfDD(oDD)) {
24342 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
24343 var loc = this.getLocation(oDD);
24345 this.locationCache[oDD.id] = loc;
24347 delete this.locationCache[oDD.id];
24348 // this will unregister the drag and drop object if
24349 // the element is not in a usable state
24358 * This checks to make sure an element exists and is in the DOM. The
24359 * main purpose is to handle cases where innerHTML is used to remove
24360 * drag and drop objects from the DOM. IE provides an 'unspecified
24361 * error' when trying to access the offsetParent of such an element
24363 * @param {HTMLElement} el the element to check
24364 * @return {boolean} true if the element looks usable
24367 verifyEl: function(el) {
24372 parent = el.offsetParent;
24375 parent = el.offsetParent;
24386 * Returns a Region object containing the drag and drop element's position
24387 * and size, including the padding configured for it
24388 * @method getLocation
24389 * @param {DragDrop} oDD the drag and drop object to get the
24391 * @return {Roo.lib.Region} a Region object representing the total area
24392 * the element occupies, including any padding
24393 * the instance is configured for.
24396 getLocation: function(oDD) {
24397 if (! this.isTypeOfDD(oDD)) {
24401 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
24404 pos= Roo.lib.Dom.getXY(el);
24412 x2 = x1 + el.offsetWidth;
24414 y2 = y1 + el.offsetHeight;
24416 t = y1 - oDD.padding[0];
24417 r = x2 + oDD.padding[1];
24418 b = y2 + oDD.padding[2];
24419 l = x1 - oDD.padding[3];
24421 return new Roo.lib.Region( t, r, b, l );
24425 * Checks the cursor location to see if it over the target
24426 * @method isOverTarget
24427 * @param {Roo.lib.Point} pt The point to evaluate
24428 * @param {DragDrop} oTarget the DragDrop object we are inspecting
24429 * @return {boolean} true if the mouse is over the target
24433 isOverTarget: function(pt, oTarget, intersect) {
24434 // use cache if available
24435 var loc = this.locationCache[oTarget.id];
24436 if (!loc || !this.useCache) {
24437 loc = this.getLocation(oTarget);
24438 this.locationCache[oTarget.id] = loc;
24446 oTarget.cursorIsOver = loc.contains( pt );
24448 // DragDrop is using this as a sanity check for the initial mousedown
24449 // in this case we are done. In POINT mode, if the drag obj has no
24450 // contraints, we are also done. Otherwise we need to evaluate the
24451 // location of the target as related to the actual location of the
24452 // dragged element.
24453 var dc = this.dragCurrent;
24454 if (!dc || !dc.getTargetCoord ||
24455 (!intersect && !dc.constrainX && !dc.constrainY)) {
24456 return oTarget.cursorIsOver;
24459 oTarget.overlap = null;
24461 // Get the current location of the drag element, this is the
24462 // location of the mouse event less the delta that represents
24463 // where the original mousedown happened on the element. We
24464 // need to consider constraints and ticks as well.
24465 var pos = dc.getTargetCoord(pt.x, pt.y);
24467 var el = dc.getDragEl();
24468 var curRegion = new Roo.lib.Region( pos.y,
24469 pos.x + el.offsetWidth,
24470 pos.y + el.offsetHeight,
24473 var overlap = curRegion.intersect(loc);
24476 oTarget.overlap = overlap;
24477 return (intersect) ? true : oTarget.cursorIsOver;
24484 * unload event handler
24485 * @method _onUnload
24489 _onUnload: function(e, me) {
24490 Roo.dd.DragDropMgr.unregAll();
24494 * Cleans up the drag and drop events and objects.
24499 unregAll: function() {
24501 if (this.dragCurrent) {
24503 this.dragCurrent = null;
24506 this._execOnAll("unreg", []);
24508 for (i in this.elementCache) {
24509 delete this.elementCache[i];
24512 this.elementCache = {};
24517 * A cache of DOM elements
24518 * @property elementCache
24525 * Get the wrapper for the DOM element specified
24526 * @method getElWrapper
24527 * @param {String} id the id of the element to get
24528 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
24530 * @deprecated This wrapper isn't that useful
24533 getElWrapper: function(id) {
24534 var oWrapper = this.elementCache[id];
24535 if (!oWrapper || !oWrapper.el) {
24536 oWrapper = this.elementCache[id] =
24537 new this.ElementWrapper(Roo.getDom(id));
24543 * Returns the actual DOM element
24544 * @method getElement
24545 * @param {String} id the id of the elment to get
24546 * @return {Object} The element
24547 * @deprecated use Roo.getDom instead
24550 getElement: function(id) {
24551 return Roo.getDom(id);
24555 * Returns the style property for the DOM element (i.e.,
24556 * document.getElById(id).style)
24558 * @param {String} id the id of the elment to get
24559 * @return {Object} The style property of the element
24560 * @deprecated use Roo.getDom instead
24563 getCss: function(id) {
24564 var el = Roo.getDom(id);
24565 return (el) ? el.style : null;
24569 * Inner class for cached elements
24570 * @class DragDropMgr.ElementWrapper
24575 ElementWrapper: function(el) {
24580 this.el = el || null;
24585 this.id = this.el && el.id;
24587 * A reference to the style property
24590 this.css = this.el && el.style;
24594 * Returns the X position of an html element
24596 * @param el the element for which to get the position
24597 * @return {int} the X coordinate
24599 * @deprecated use Roo.lib.Dom.getX instead
24602 getPosX: function(el) {
24603 return Roo.lib.Dom.getX(el);
24607 * Returns the Y position of an html element
24609 * @param el the element for which to get the position
24610 * @return {int} the Y coordinate
24611 * @deprecated use Roo.lib.Dom.getY instead
24614 getPosY: function(el) {
24615 return Roo.lib.Dom.getY(el);
24619 * Swap two nodes. In IE, we use the native method, for others we
24620 * emulate the IE behavior
24622 * @param n1 the first node to swap
24623 * @param n2 the other node to swap
24626 swapNode: function(n1, n2) {
24630 var p = n2.parentNode;
24631 var s = n2.nextSibling;
24634 p.insertBefore(n1, n2);
24635 } else if (n2 == n1.nextSibling) {
24636 p.insertBefore(n2, n1);
24638 n1.parentNode.replaceChild(n2, n1);
24639 p.insertBefore(n1, s);
24645 * Returns the current scroll position
24646 * @method getScroll
24650 getScroll: function () {
24651 var t, l, dde=document.documentElement, db=document.body;
24652 if (dde && (dde.scrollTop || dde.scrollLeft)) {
24654 l = dde.scrollLeft;
24661 return { top: t, left: l };
24665 * Returns the specified element style property
24667 * @param {HTMLElement} el the element
24668 * @param {string} styleProp the style property
24669 * @return {string} The value of the style property
24670 * @deprecated use Roo.lib.Dom.getStyle
24673 getStyle: function(el, styleProp) {
24674 return Roo.fly(el).getStyle(styleProp);
24678 * Gets the scrollTop
24679 * @method getScrollTop
24680 * @return {int} the document's scrollTop
24683 getScrollTop: function () { return this.getScroll().top; },
24686 * Gets the scrollLeft
24687 * @method getScrollLeft
24688 * @return {int} the document's scrollTop
24691 getScrollLeft: function () { return this.getScroll().left; },
24694 * Sets the x/y position of an element to the location of the
24697 * @param {HTMLElement} moveEl The element to move
24698 * @param {HTMLElement} targetEl The position reference element
24701 moveToEl: function (moveEl, targetEl) {
24702 var aCoord = Roo.lib.Dom.getXY(targetEl);
24703 Roo.lib.Dom.setXY(moveEl, aCoord);
24707 * Numeric array sort function
24708 * @method numericSort
24711 numericSort: function(a, b) { return (a - b); },
24715 * @property _timeoutCount
24722 * Trying to make the load order less important. Without this we get
24723 * an error if this file is loaded before the Event Utility.
24724 * @method _addListeners
24728 _addListeners: function() {
24729 var DDM = Roo.dd.DDM;
24730 if ( Roo.lib.Event && document ) {
24733 if (DDM._timeoutCount > 2000) {
24735 setTimeout(DDM._addListeners, 10);
24736 if (document && document.body) {
24737 DDM._timeoutCount += 1;
24744 * Recursively searches the immediate parent and all child nodes for
24745 * the handle element in order to determine wheter or not it was
24747 * @method handleWasClicked
24748 * @param node the html element to inspect
24751 handleWasClicked: function(node, id) {
24752 if (this.isHandle(id, node.id)) {
24755 // check to see if this is a text node child of the one we want
24756 var p = node.parentNode;
24759 if (this.isHandle(id, p.id)) {
24774 // shorter alias, save a few bytes
24775 Roo.dd.DDM = Roo.dd.DragDropMgr;
24776 Roo.dd.DDM._addListeners();
24780 * Ext JS Library 1.1.1
24781 * Copyright(c) 2006-2007, Ext JS, LLC.
24783 * Originally Released Under LGPL - original licence link has changed is not relivant.
24786 * <script type="text/javascript">
24791 * A DragDrop implementation where the linked element follows the
24792 * mouse cursor during a drag.
24793 * @extends Roo.dd.DragDrop
24795 * @param {String} id the id of the linked element
24796 * @param {String} sGroup the group of related DragDrop items
24797 * @param {object} config an object containing configurable attributes
24798 * Valid properties for DD:
24801 Roo.dd.DD = function(id, sGroup, config) {
24803 this.init(id, sGroup, config);
24807 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
24810 * When set to true, the utility automatically tries to scroll the browser
24811 * window wehn a drag and drop element is dragged near the viewport boundary.
24812 * Defaults to true.
24819 * Sets the pointer offset to the distance between the linked element's top
24820 * left corner and the location the element was clicked
24821 * @method autoOffset
24822 * @param {int} iPageX the X coordinate of the click
24823 * @param {int} iPageY the Y coordinate of the click
24825 autoOffset: function(iPageX, iPageY) {
24826 var x = iPageX - this.startPageX;
24827 var y = iPageY - this.startPageY;
24828 this.setDelta(x, y);
24832 * Sets the pointer offset. You can call this directly to force the
24833 * offset to be in a particular location (e.g., pass in 0,0 to set it
24834 * to the center of the object)
24836 * @param {int} iDeltaX the distance from the left
24837 * @param {int} iDeltaY the distance from the top
24839 setDelta: function(iDeltaX, iDeltaY) {
24840 this.deltaX = iDeltaX;
24841 this.deltaY = iDeltaY;
24845 * Sets the drag element to the location of the mousedown or click event,
24846 * maintaining the cursor location relative to the location on the element
24847 * that was clicked. Override this if you want to place the element in a
24848 * location other than where the cursor is.
24849 * @method setDragElPos
24850 * @param {int} iPageX the X coordinate of the mousedown or drag event
24851 * @param {int} iPageY the Y coordinate of the mousedown or drag event
24853 setDragElPos: function(iPageX, iPageY) {
24854 // the first time we do this, we are going to check to make sure
24855 // the element has css positioning
24857 var el = this.getDragEl();
24858 this.alignElWithMouse(el, iPageX, iPageY);
24862 * Sets the element to the location of the mousedown or click event,
24863 * maintaining the cursor location relative to the location on the element
24864 * that was clicked. Override this if you want to place the element in a
24865 * location other than where the cursor is.
24866 * @method alignElWithMouse
24867 * @param {HTMLElement} el the element to move
24868 * @param {int} iPageX the X coordinate of the mousedown or drag event
24869 * @param {int} iPageY the Y coordinate of the mousedown or drag event
24871 alignElWithMouse: function(el, iPageX, iPageY) {
24872 var oCoord = this.getTargetCoord(iPageX, iPageY);
24873 var fly = el.dom ? el : Roo.fly(el);
24874 if (!this.deltaSetXY) {
24875 var aCoord = [oCoord.x, oCoord.y];
24877 var newLeft = fly.getLeft(true);
24878 var newTop = fly.getTop(true);
24879 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
24881 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
24884 this.cachePosition(oCoord.x, oCoord.y);
24885 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
24890 * Saves the most recent position so that we can reset the constraints and
24891 * tick marks on-demand. We need to know this so that we can calculate the
24892 * number of pixels the element is offset from its original position.
24893 * @method cachePosition
24894 * @param iPageX the current x position (optional, this just makes it so we
24895 * don't have to look it up again)
24896 * @param iPageY the current y position (optional, this just makes it so we
24897 * don't have to look it up again)
24899 cachePosition: function(iPageX, iPageY) {
24901 this.lastPageX = iPageX;
24902 this.lastPageY = iPageY;
24904 var aCoord = Roo.lib.Dom.getXY(this.getEl());
24905 this.lastPageX = aCoord[0];
24906 this.lastPageY = aCoord[1];
24911 * Auto-scroll the window if the dragged object has been moved beyond the
24912 * visible window boundary.
24913 * @method autoScroll
24914 * @param {int} x the drag element's x position
24915 * @param {int} y the drag element's y position
24916 * @param {int} h the height of the drag element
24917 * @param {int} w the width of the drag element
24920 autoScroll: function(x, y, h, w) {
24923 // The client height
24924 var clientH = Roo.lib.Dom.getViewWidth();
24926 // The client width
24927 var clientW = Roo.lib.Dom.getViewHeight();
24929 // The amt scrolled down
24930 var st = this.DDM.getScrollTop();
24932 // The amt scrolled right
24933 var sl = this.DDM.getScrollLeft();
24935 // Location of the bottom of the element
24938 // Location of the right of the element
24941 // The distance from the cursor to the bottom of the visible area,
24942 // adjusted so that we don't scroll if the cursor is beyond the
24943 // element drag constraints
24944 var toBot = (clientH + st - y - this.deltaY);
24946 // The distance from the cursor to the right of the visible area
24947 var toRight = (clientW + sl - x - this.deltaX);
24950 // How close to the edge the cursor must be before we scroll
24951 // var thresh = (document.all) ? 100 : 40;
24954 // How many pixels to scroll per autoscroll op. This helps to reduce
24955 // clunky scrolling. IE is more sensitive about this ... it needs this
24956 // value to be higher.
24957 var scrAmt = (document.all) ? 80 : 30;
24959 // Scroll down if we are near the bottom of the visible page and the
24960 // obj extends below the crease
24961 if ( bot > clientH && toBot < thresh ) {
24962 window.scrollTo(sl, st + scrAmt);
24965 // Scroll up if the window is scrolled down and the top of the object
24966 // goes above the top border
24967 if ( y < st && st > 0 && y - st < thresh ) {
24968 window.scrollTo(sl, st - scrAmt);
24971 // Scroll right if the obj is beyond the right border and the cursor is
24972 // near the border.
24973 if ( right > clientW && toRight < thresh ) {
24974 window.scrollTo(sl + scrAmt, st);
24977 // Scroll left if the window has been scrolled to the right and the obj
24978 // extends past the left border
24979 if ( x < sl && sl > 0 && x - sl < thresh ) {
24980 window.scrollTo(sl - scrAmt, st);
24986 * Finds the location the element should be placed if we want to move
24987 * it to where the mouse location less the click offset would place us.
24988 * @method getTargetCoord
24989 * @param {int} iPageX the X coordinate of the click
24990 * @param {int} iPageY the Y coordinate of the click
24991 * @return an object that contains the coordinates (Object.x and Object.y)
24994 getTargetCoord: function(iPageX, iPageY) {
24997 var x = iPageX - this.deltaX;
24998 var y = iPageY - this.deltaY;
25000 if (this.constrainX) {
25001 if (x < this.minX) { x = this.minX; }
25002 if (x > this.maxX) { x = this.maxX; }
25005 if (this.constrainY) {
25006 if (y < this.minY) { y = this.minY; }
25007 if (y > this.maxY) { y = this.maxY; }
25010 x = this.getTick(x, this.xTicks);
25011 y = this.getTick(y, this.yTicks);
25018 * Sets up config options specific to this class. Overrides
25019 * Roo.dd.DragDrop, but all versions of this method through the
25020 * inheritance chain are called
25022 applyConfig: function() {
25023 Roo.dd.DD.superclass.applyConfig.call(this);
25024 this.scroll = (this.config.scroll !== false);
25028 * Event that fires prior to the onMouseDown event. Overrides
25031 b4MouseDown: function(e) {
25032 // this.resetConstraints();
25033 this.autoOffset(e.getPageX(),
25038 * Event that fires prior to the onDrag event. Overrides
25041 b4Drag: function(e) {
25042 this.setDragElPos(e.getPageX(),
25046 toString: function() {
25047 return ("DD " + this.id);
25050 //////////////////////////////////////////////////////////////////////////
25051 // Debugging ygDragDrop events that can be overridden
25052 //////////////////////////////////////////////////////////////////////////
25054 startDrag: function(x, y) {
25057 onDrag: function(e) {
25060 onDragEnter: function(e, id) {
25063 onDragOver: function(e, id) {
25066 onDragOut: function(e, id) {
25069 onDragDrop: function(e, id) {
25072 endDrag: function(e) {
25079 * Ext JS Library 1.1.1
25080 * Copyright(c) 2006-2007, Ext JS, LLC.
25082 * Originally Released Under LGPL - original licence link has changed is not relivant.
25085 * <script type="text/javascript">
25089 * @class Roo.dd.DDProxy
25090 * A DragDrop implementation that inserts an empty, bordered div into
25091 * the document that follows the cursor during drag operations. At the time of
25092 * the click, the frame div is resized to the dimensions of the linked html
25093 * element, and moved to the exact location of the linked element.
25095 * References to the "frame" element refer to the single proxy element that
25096 * was created to be dragged in place of all DDProxy elements on the
25099 * @extends Roo.dd.DD
25101 * @param {String} id the id of the linked html element
25102 * @param {String} sGroup the group of related DragDrop objects
25103 * @param {object} config an object containing configurable attributes
25104 * Valid properties for DDProxy in addition to those in DragDrop:
25105 * resizeFrame, centerFrame, dragElId
25107 Roo.dd.DDProxy = function(id, sGroup, config) {
25109 this.init(id, sGroup, config);
25115 * The default drag frame div id
25116 * @property Roo.dd.DDProxy.dragElId
25120 Roo.dd.DDProxy.dragElId = "ygddfdiv";
25122 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
25125 * By default we resize the drag frame to be the same size as the element
25126 * we want to drag (this is to get the frame effect). We can turn it off
25127 * if we want a different behavior.
25128 * @property resizeFrame
25134 * By default the frame is positioned exactly where the drag element is, so
25135 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
25136 * you do not have constraints on the obj is to have the drag frame centered
25137 * around the cursor. Set centerFrame to true for this effect.
25138 * @property centerFrame
25141 centerFrame: false,
25144 * Creates the proxy element if it does not yet exist
25145 * @method createFrame
25147 createFrame: function() {
25149 var body = document.body;
25151 if (!body || !body.firstChild) {
25152 setTimeout( function() { self.createFrame(); }, 50 );
25156 var div = this.getDragEl();
25159 div = document.createElement("div");
25160 div.id = this.dragElId;
25163 s.position = "absolute";
25164 s.visibility = "hidden";
25166 s.border = "2px solid #aaa";
25169 // appendChild can blow up IE if invoked prior to the window load event
25170 // while rendering a table. It is possible there are other scenarios
25171 // that would cause this to happen as well.
25172 body.insertBefore(div, body.firstChild);
25177 * Initialization for the drag frame element. Must be called in the
25178 * constructor of all subclasses
25179 * @method initFrame
25181 initFrame: function() {
25182 this.createFrame();
25185 applyConfig: function() {
25186 Roo.dd.DDProxy.superclass.applyConfig.call(this);
25188 this.resizeFrame = (this.config.resizeFrame !== false);
25189 this.centerFrame = (this.config.centerFrame);
25190 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
25194 * Resizes the drag frame to the dimensions of the clicked object, positions
25195 * it over the object, and finally displays it
25196 * @method showFrame
25197 * @param {int} iPageX X click position
25198 * @param {int} iPageY Y click position
25201 showFrame: function(iPageX, iPageY) {
25202 var el = this.getEl();
25203 var dragEl = this.getDragEl();
25204 var s = dragEl.style;
25206 this._resizeProxy();
25208 if (this.centerFrame) {
25209 this.setDelta( Math.round(parseInt(s.width, 10)/2),
25210 Math.round(parseInt(s.height, 10)/2) );
25213 this.setDragElPos(iPageX, iPageY);
25215 Roo.fly(dragEl).show();
25219 * The proxy is automatically resized to the dimensions of the linked
25220 * element when a drag is initiated, unless resizeFrame is set to false
25221 * @method _resizeProxy
25224 _resizeProxy: function() {
25225 if (this.resizeFrame) {
25226 var el = this.getEl();
25227 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
25231 // overrides Roo.dd.DragDrop
25232 b4MouseDown: function(e) {
25233 var x = e.getPageX();
25234 var y = e.getPageY();
25235 this.autoOffset(x, y);
25236 this.setDragElPos(x, y);
25239 // overrides Roo.dd.DragDrop
25240 b4StartDrag: function(x, y) {
25241 // show the drag frame
25242 this.showFrame(x, y);
25245 // overrides Roo.dd.DragDrop
25246 b4EndDrag: function(e) {
25247 Roo.fly(this.getDragEl()).hide();
25250 // overrides Roo.dd.DragDrop
25251 // By default we try to move the element to the last location of the frame.
25252 // This is so that the default behavior mirrors that of Roo.dd.DD.
25253 endDrag: function(e) {
25255 var lel = this.getEl();
25256 var del = this.getDragEl();
25258 // Show the drag frame briefly so we can get its position
25259 del.style.visibility = "";
25262 // Hide the linked element before the move to get around a Safari
25264 lel.style.visibility = "hidden";
25265 Roo.dd.DDM.moveToEl(lel, del);
25266 del.style.visibility = "hidden";
25267 lel.style.visibility = "";
25272 beforeMove : function(){
25276 afterDrag : function(){
25280 toString: function() {
25281 return ("DDProxy " + this.id);
25287 * Ext JS Library 1.1.1
25288 * Copyright(c) 2006-2007, Ext JS, LLC.
25290 * Originally Released Under LGPL - original licence link has changed is not relivant.
25293 * <script type="text/javascript">
25297 * @class Roo.dd.DDTarget
25298 * A DragDrop implementation that does not move, but can be a drop
25299 * target. You would get the same result by simply omitting implementation
25300 * for the event callbacks, but this way we reduce the processing cost of the
25301 * event listener and the callbacks.
25302 * @extends Roo.dd.DragDrop
25304 * @param {String} id the id of the element that is a drop target
25305 * @param {String} sGroup the group of related DragDrop objects
25306 * @param {object} config an object containing configurable attributes
25307 * Valid properties for DDTarget in addition to those in
25311 Roo.dd.DDTarget = function(id, sGroup, config) {
25313 this.initTarget(id, sGroup, config);
25315 if (config.listeners || config.events) {
25316 Roo.dd.DragDrop.superclass.constructor.call(this, {
25317 listeners : config.listeners || {},
25318 events : config.events || {}
25323 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
25324 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
25325 toString: function() {
25326 return ("DDTarget " + this.id);
25331 * Ext JS Library 1.1.1
25332 * Copyright(c) 2006-2007, Ext JS, LLC.
25334 * Originally Released Under LGPL - original licence link has changed is not relivant.
25337 * <script type="text/javascript">
25342 * @class Roo.dd.ScrollManager
25343 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
25344 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
25347 Roo.dd.ScrollManager = function(){
25348 var ddm = Roo.dd.DragDropMgr;
25355 var onStop = function(e){
25360 var triggerRefresh = function(){
25361 if(ddm.dragCurrent){
25362 ddm.refreshCache(ddm.dragCurrent.groups);
25366 var doScroll = function(){
25367 if(ddm.dragCurrent){
25368 var dds = Roo.dd.ScrollManager;
25370 if(proc.el.scroll(proc.dir, dds.increment)){
25374 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
25379 var clearProc = function(){
25381 clearInterval(proc.id);
25388 var startProc = function(el, dir){
25389 Roo.log('scroll startproc');
25393 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
25396 var onFire = function(e, isDrop){
25398 if(isDrop || !ddm.dragCurrent){ return; }
25399 var dds = Roo.dd.ScrollManager;
25400 if(!dragEl || dragEl != ddm.dragCurrent){
25401 dragEl = ddm.dragCurrent;
25402 // refresh regions on drag start
25403 dds.refreshCache();
25406 var xy = Roo.lib.Event.getXY(e);
25407 var pt = new Roo.lib.Point(xy[0], xy[1]);
25408 for(var id in els){
25409 var el = els[id], r = el._region;
25410 if(r && r.contains(pt) && el.isScrollable()){
25411 if(r.bottom - pt.y <= dds.thresh){
25413 startProc(el, "down");
25416 }else if(r.right - pt.x <= dds.thresh){
25418 startProc(el, "left");
25421 }else if(pt.y - r.top <= dds.thresh){
25423 startProc(el, "up");
25426 }else if(pt.x - r.left <= dds.thresh){
25428 startProc(el, "right");
25437 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
25438 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
25442 * Registers new overflow element(s) to auto scroll
25443 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
25445 register : function(el){
25446 if(el instanceof Array){
25447 for(var i = 0, len = el.length; i < len; i++) {
25448 this.register(el[i]);
25454 Roo.dd.ScrollManager.els = els;
25458 * Unregisters overflow element(s) so they are no longer scrolled
25459 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
25461 unregister : function(el){
25462 if(el instanceof Array){
25463 for(var i = 0, len = el.length; i < len; i++) {
25464 this.unregister(el[i]);
25473 * The number of pixels from the edge of a container the pointer needs to be to
25474 * trigger scrolling (defaults to 25)
25480 * The number of pixels to scroll in each scroll increment (defaults to 50)
25486 * The frequency of scrolls in milliseconds (defaults to 500)
25492 * True to animate the scroll (defaults to true)
25498 * The animation duration in seconds -
25499 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
25505 * Manually trigger a cache refresh.
25507 refreshCache : function(){
25508 for(var id in els){
25509 if(typeof els[id] == 'object'){ // for people extending the object prototype
25510 els[id]._region = els[id].getRegion();
25517 * Ext JS Library 1.1.1
25518 * Copyright(c) 2006-2007, Ext JS, LLC.
25520 * Originally Released Under LGPL - original licence link has changed is not relivant.
25523 * <script type="text/javascript">
25528 * @class Roo.dd.Registry
25529 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
25530 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
25533 Roo.dd.Registry = function(){
25536 var autoIdSeed = 0;
25538 var getId = function(el, autogen){
25539 if(typeof el == "string"){
25543 if(!id && autogen !== false){
25544 id = "roodd-" + (++autoIdSeed);
25552 * Register a drag drop element
25553 * @param {String|HTMLElement} element The id or DOM node to register
25554 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
25555 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
25556 * knows how to interpret, plus there are some specific properties known to the Registry that should be
25557 * populated in the data object (if applicable):
25559 Value Description<br />
25560 --------- ------------------------------------------<br />
25561 handles Array of DOM nodes that trigger dragging<br />
25562 for the element being registered<br />
25563 isHandle True if the element passed in triggers<br />
25564 dragging itself, else false
25567 register : function(el, data){
25569 if(typeof el == "string"){
25570 el = document.getElementById(el);
25573 elements[getId(el)] = data;
25574 if(data.isHandle !== false){
25575 handles[data.ddel.id] = data;
25578 var hs = data.handles;
25579 for(var i = 0, len = hs.length; i < len; i++){
25580 handles[getId(hs[i])] = data;
25586 * Unregister a drag drop element
25587 * @param {String|HTMLElement} element The id or DOM node to unregister
25589 unregister : function(el){
25590 var id = getId(el, false);
25591 var data = elements[id];
25593 delete elements[id];
25595 var hs = data.handles;
25596 for(var i = 0, len = hs.length; i < len; i++){
25597 delete handles[getId(hs[i], false)];
25604 * Returns the handle registered for a DOM Node by id
25605 * @param {String|HTMLElement} id The DOM node or id to look up
25606 * @return {Object} handle The custom handle data
25608 getHandle : function(id){
25609 if(typeof id != "string"){ // must be element?
25612 return handles[id];
25616 * Returns the handle that is registered for the DOM node that is the target of the event
25617 * @param {Event} e The event
25618 * @return {Object} handle The custom handle data
25620 getHandleFromEvent : function(e){
25621 var t = Roo.lib.Event.getTarget(e);
25622 return t ? handles[t.id] : null;
25626 * Returns a custom data object that is registered for a DOM node by id
25627 * @param {String|HTMLElement} id The DOM node or id to look up
25628 * @return {Object} data The custom data
25630 getTarget : function(id){
25631 if(typeof id != "string"){ // must be element?
25634 return elements[id];
25638 * Returns a custom data object that is registered for the DOM node that is the target of the event
25639 * @param {Event} e The event
25640 * @return {Object} data The custom data
25642 getTargetFromEvent : function(e){
25643 var t = Roo.lib.Event.getTarget(e);
25644 return t ? elements[t.id] || handles[t.id] : null;
25649 * Ext JS Library 1.1.1
25650 * Copyright(c) 2006-2007, Ext JS, LLC.
25652 * Originally Released Under LGPL - original licence link has changed is not relivant.
25655 * <script type="text/javascript">
25660 * @class Roo.dd.StatusProxy
25661 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
25662 * default drag proxy used by all Roo.dd components.
25664 * @param {Object} config
25666 Roo.dd.StatusProxy = function(config){
25667 Roo.apply(this, config);
25668 this.id = this.id || Roo.id();
25669 this.el = new Roo.Layer({
25671 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
25672 {tag: "div", cls: "x-dd-drop-icon"},
25673 {tag: "div", cls: "x-dd-drag-ghost"}
25676 shadow: !config || config.shadow !== false
25678 this.ghost = Roo.get(this.el.dom.childNodes[1]);
25679 this.dropStatus = this.dropNotAllowed;
25682 Roo.dd.StatusProxy.prototype = {
25684 * @cfg {String} dropAllowed
25685 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
25687 dropAllowed : "x-dd-drop-ok",
25689 * @cfg {String} dropNotAllowed
25690 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
25692 dropNotAllowed : "x-dd-drop-nodrop",
25695 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
25696 * over the current target element.
25697 * @param {String} cssClass The css class for the new drop status indicator image
25699 setStatus : function(cssClass){
25700 cssClass = cssClass || this.dropNotAllowed;
25701 if(this.dropStatus != cssClass){
25702 this.el.replaceClass(this.dropStatus, cssClass);
25703 this.dropStatus = cssClass;
25708 * Resets the status indicator to the default dropNotAllowed value
25709 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
25711 reset : function(clearGhost){
25712 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
25713 this.dropStatus = this.dropNotAllowed;
25715 this.ghost.update("");
25720 * Updates the contents of the ghost element
25721 * @param {String} html The html that will replace the current innerHTML of the ghost element
25723 update : function(html){
25724 if(typeof html == "string"){
25725 this.ghost.update(html);
25727 this.ghost.update("");
25728 html.style.margin = "0";
25729 this.ghost.dom.appendChild(html);
25731 // ensure float = none set?? cant remember why though.
25732 var el = this.ghost.dom.firstChild;
25734 Roo.fly(el).setStyle('float', 'none');
25739 * Returns the underlying proxy {@link Roo.Layer}
25740 * @return {Roo.Layer} el
25742 getEl : function(){
25747 * Returns the ghost element
25748 * @return {Roo.Element} el
25750 getGhost : function(){
25756 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
25758 hide : function(clear){
25766 * Stops the repair animation if it's currently running
25769 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
25775 * Displays this proxy
25782 * Force the Layer to sync its shadow and shim positions to the element
25789 * Causes the proxy to return to its position of origin via an animation. Should be called after an
25790 * invalid drop operation by the item being dragged.
25791 * @param {Array} xy The XY position of the element ([x, y])
25792 * @param {Function} callback The function to call after the repair is complete
25793 * @param {Object} scope The scope in which to execute the callback
25795 repair : function(xy, callback, scope){
25796 this.callback = callback;
25797 this.scope = scope;
25798 if(xy && this.animRepair !== false){
25799 this.el.addClass("x-dd-drag-repair");
25800 this.el.hideUnders(true);
25801 this.anim = this.el.shift({
25802 duration: this.repairDuration || .5,
25806 callback: this.afterRepair,
25810 this.afterRepair();
25815 afterRepair : function(){
25817 if(typeof this.callback == "function"){
25818 this.callback.call(this.scope || this);
25820 this.callback = null;
25825 * Ext JS Library 1.1.1
25826 * Copyright(c) 2006-2007, Ext JS, LLC.
25828 * Originally Released Under LGPL - original licence link has changed is not relivant.
25831 * <script type="text/javascript">
25835 * @class Roo.dd.DragSource
25836 * @extends Roo.dd.DDProxy
25837 * A simple class that provides the basic implementation needed to make any element draggable.
25839 * @param {String/HTMLElement/Element} el The container element
25840 * @param {Object} config
25842 Roo.dd.DragSource = function(el, config){
25843 this.el = Roo.get(el);
25844 this.dragData = {};
25846 Roo.apply(this, config);
25849 this.proxy = new Roo.dd.StatusProxy();
25852 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
25853 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
25855 this.dragging = false;
25858 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
25860 * @cfg {String} dropAllowed
25861 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
25863 dropAllowed : "x-dd-drop-ok",
25865 * @cfg {String} dropNotAllowed
25866 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
25868 dropNotAllowed : "x-dd-drop-nodrop",
25871 * Returns the data object associated with this drag source
25872 * @return {Object} data An object containing arbitrary data
25874 getDragData : function(e){
25875 return this.dragData;
25879 onDragEnter : function(e, id){
25880 var target = Roo.dd.DragDropMgr.getDDById(id);
25881 this.cachedTarget = target;
25882 if(this.beforeDragEnter(target, e, id) !== false){
25883 if(target.isNotifyTarget){
25884 var status = target.notifyEnter(this, e, this.dragData);
25885 this.proxy.setStatus(status);
25887 this.proxy.setStatus(this.dropAllowed);
25890 if(this.afterDragEnter){
25892 * An empty function by default, but provided so that you can perform a custom action
25893 * when the dragged item enters the drop target by providing an implementation.
25894 * @param {Roo.dd.DragDrop} target The drop target
25895 * @param {Event} e The event object
25896 * @param {String} id The id of the dragged element
25897 * @method afterDragEnter
25899 this.afterDragEnter(target, e, id);
25905 * An empty function by default, but provided so that you can perform a custom action
25906 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
25907 * @param {Roo.dd.DragDrop} target The drop target
25908 * @param {Event} e The event object
25909 * @param {String} id The id of the dragged element
25910 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
25912 beforeDragEnter : function(target, e, id){
25917 alignElWithMouse: function() {
25918 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
25923 onDragOver : function(e, id){
25924 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
25925 if(this.beforeDragOver(target, e, id) !== false){
25926 if(target.isNotifyTarget){
25927 var status = target.notifyOver(this, e, this.dragData);
25928 this.proxy.setStatus(status);
25931 if(this.afterDragOver){
25933 * An empty function by default, but provided so that you can perform a custom action
25934 * while the dragged item is over the drop target by providing an implementation.
25935 * @param {Roo.dd.DragDrop} target The drop target
25936 * @param {Event} e The event object
25937 * @param {String} id The id of the dragged element
25938 * @method afterDragOver
25940 this.afterDragOver(target, e, id);
25946 * An empty function by default, but provided so that you can perform a custom action
25947 * while the dragged item is over the drop target and optionally cancel the onDragOver.
25948 * @param {Roo.dd.DragDrop} target The drop target
25949 * @param {Event} e The event object
25950 * @param {String} id The id of the dragged element
25951 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
25953 beforeDragOver : function(target, e, id){
25958 onDragOut : function(e, id){
25959 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
25960 if(this.beforeDragOut(target, e, id) !== false){
25961 if(target.isNotifyTarget){
25962 target.notifyOut(this, e, this.dragData);
25964 this.proxy.reset();
25965 if(this.afterDragOut){
25967 * An empty function by default, but provided so that you can perform a custom action
25968 * after the dragged item is dragged out of the target without dropping.
25969 * @param {Roo.dd.DragDrop} target The drop target
25970 * @param {Event} e The event object
25971 * @param {String} id The id of the dragged element
25972 * @method afterDragOut
25974 this.afterDragOut(target, e, id);
25977 this.cachedTarget = null;
25981 * An empty function by default, but provided so that you can perform a custom action before the dragged
25982 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
25983 * @param {Roo.dd.DragDrop} target The drop target
25984 * @param {Event} e The event object
25985 * @param {String} id The id of the dragged element
25986 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
25988 beforeDragOut : function(target, e, id){
25993 onDragDrop : function(e, id){
25994 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
25995 if(this.beforeDragDrop(target, e, id) !== false){
25996 if(target.isNotifyTarget){
25997 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
25998 this.onValidDrop(target, e, id);
26000 this.onInvalidDrop(target, e, id);
26003 this.onValidDrop(target, e, id);
26006 if(this.afterDragDrop){
26008 * An empty function by default, but provided so that you can perform a custom action
26009 * after a valid drag drop has occurred by providing an implementation.
26010 * @param {Roo.dd.DragDrop} target The drop target
26011 * @param {Event} e The event object
26012 * @param {String} id The id of the dropped element
26013 * @method afterDragDrop
26015 this.afterDragDrop(target, e, id);
26018 delete this.cachedTarget;
26022 * An empty function by default, but provided so that you can perform a custom action before the dragged
26023 * item is dropped onto the target and optionally cancel the onDragDrop.
26024 * @param {Roo.dd.DragDrop} target The drop target
26025 * @param {Event} e The event object
26026 * @param {String} id The id of the dragged element
26027 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
26029 beforeDragDrop : function(target, e, id){
26034 onValidDrop : function(target, e, id){
26036 if(this.afterValidDrop){
26038 * An empty function by default, but provided so that you can perform a custom action
26039 * after a valid drop has occurred by providing an implementation.
26040 * @param {Object} target The target DD
26041 * @param {Event} e The event object
26042 * @param {String} id The id of the dropped element
26043 * @method afterInvalidDrop
26045 this.afterValidDrop(target, e, id);
26050 getRepairXY : function(e, data){
26051 return this.el.getXY();
26055 onInvalidDrop : function(target, e, id){
26056 this.beforeInvalidDrop(target, e, id);
26057 if(this.cachedTarget){
26058 if(this.cachedTarget.isNotifyTarget){
26059 this.cachedTarget.notifyOut(this, e, this.dragData);
26061 this.cacheTarget = null;
26063 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
26065 if(this.afterInvalidDrop){
26067 * An empty function by default, but provided so that you can perform a custom action
26068 * after an invalid drop has occurred by providing an implementation.
26069 * @param {Event} e The event object
26070 * @param {String} id The id of the dropped element
26071 * @method afterInvalidDrop
26073 this.afterInvalidDrop(e, id);
26078 afterRepair : function(){
26080 this.el.highlight(this.hlColor || "c3daf9");
26082 this.dragging = false;
26086 * An empty function by default, but provided so that you can perform a custom action after an invalid
26087 * drop has occurred.
26088 * @param {Roo.dd.DragDrop} target The drop target
26089 * @param {Event} e The event object
26090 * @param {String} id The id of the dragged element
26091 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
26093 beforeInvalidDrop : function(target, e, id){
26098 handleMouseDown : function(e){
26099 if(this.dragging) {
26102 var data = this.getDragData(e);
26103 if(data && this.onBeforeDrag(data, e) !== false){
26104 this.dragData = data;
26106 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
26111 * An empty function by default, but provided so that you can perform a custom action before the initial
26112 * drag event begins and optionally cancel it.
26113 * @param {Object} data An object containing arbitrary data to be shared with drop targets
26114 * @param {Event} e The event object
26115 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
26117 onBeforeDrag : function(data, e){
26122 * An empty function by default, but provided so that you can perform a custom action once the initial
26123 * drag event has begun. The drag cannot be canceled from this function.
26124 * @param {Number} x The x position of the click on the dragged object
26125 * @param {Number} y The y position of the click on the dragged object
26127 onStartDrag : Roo.emptyFn,
26129 // private - YUI override
26130 startDrag : function(x, y){
26131 this.proxy.reset();
26132 this.dragging = true;
26133 this.proxy.update("");
26134 this.onInitDrag(x, y);
26139 onInitDrag : function(x, y){
26140 var clone = this.el.dom.cloneNode(true);
26141 clone.id = Roo.id(); // prevent duplicate ids
26142 this.proxy.update(clone);
26143 this.onStartDrag(x, y);
26148 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
26149 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
26151 getProxy : function(){
26156 * Hides the drag source's {@link Roo.dd.StatusProxy}
26158 hideProxy : function(){
26160 this.proxy.reset(true);
26161 this.dragging = false;
26165 triggerCacheRefresh : function(){
26166 Roo.dd.DDM.refreshCache(this.groups);
26169 // private - override to prevent hiding
26170 b4EndDrag: function(e) {
26173 // private - override to prevent moving
26174 endDrag : function(e){
26175 this.onEndDrag(this.dragData, e);
26179 onEndDrag : function(data, e){
26182 // private - pin to cursor
26183 autoOffset : function(x, y) {
26184 this.setDelta(-12, -20);
26188 * Ext JS Library 1.1.1
26189 * Copyright(c) 2006-2007, Ext JS, LLC.
26191 * Originally Released Under LGPL - original licence link has changed is not relivant.
26194 * <script type="text/javascript">
26199 * @class Roo.dd.DropTarget
26200 * @extends Roo.dd.DDTarget
26201 * A simple class that provides the basic implementation needed to make any element a drop target that can have
26202 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
26204 * @param {String/HTMLElement/Element} el The container element
26205 * @param {Object} config
26207 Roo.dd.DropTarget = function(el, config){
26208 this.el = Roo.get(el);
26210 var listeners = false; ;
26211 if (config && config.listeners) {
26212 listeners= config.listeners;
26213 delete config.listeners;
26215 Roo.apply(this, config);
26217 if(this.containerScroll){
26218 Roo.dd.ScrollManager.register(this.el);
26222 * @scope Roo.dd.DropTarget
26227 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
26228 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
26229 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
26231 * IMPORTANT : it should set this.overClass and this.dropAllowed
26233 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
26234 * @param {Event} e The event
26235 * @param {Object} data An object containing arbitrary data supplied by the drag source
26241 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
26242 * This method will be called on every mouse movement while the drag source is over the drop target.
26243 * This default implementation simply returns the dropAllowed config value.
26245 * IMPORTANT : it should set this.dropAllowed
26247 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
26248 * @param {Event} e The event
26249 * @param {Object} data An object containing arbitrary data supplied by the drag source
26255 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
26256 * out of the target without dropping. This default implementation simply removes the CSS class specified by
26257 * overClass (if any) from the drop element.
26259 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
26260 * @param {Event} e The event
26261 * @param {Object} data An object containing arbitrary data supplied by the drag source
26267 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
26268 * been dropped on it. This method has no default implementation and returns false, so you must provide an
26269 * implementation that does something to process the drop event and returns true so that the drag source's
26270 * repair action does not run.
26272 * IMPORTANT : it should set this.success
26274 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
26275 * @param {Event} e The event
26276 * @param {Object} data An object containing arbitrary data supplied by the drag source
26282 Roo.dd.DropTarget.superclass.constructor.call( this,
26284 this.ddGroup || this.group,
26287 listeners : listeners || {}
26295 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
26297 * @cfg {String} overClass
26298 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
26301 * @cfg {String} ddGroup
26302 * The drag drop group to handle drop events for
26306 * @cfg {String} dropAllowed
26307 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
26309 dropAllowed : "x-dd-drop-ok",
26311 * @cfg {String} dropNotAllowed
26312 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
26314 dropNotAllowed : "x-dd-drop-nodrop",
26316 * @cfg {boolean} success
26317 * set this after drop listener..
26321 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
26322 * if the drop point is valid for over/enter..
26329 isNotifyTarget : true,
26334 notifyEnter : function(dd, e, data)
26337 this.fireEvent('enter', dd, e, data);
26338 if(this.overClass){
26339 this.el.addClass(this.overClass);
26341 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
26342 this.valid ? this.dropAllowed : this.dropNotAllowed
26349 notifyOver : function(dd, e, data)
26352 this.fireEvent('over', dd, e, data);
26353 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
26354 this.valid ? this.dropAllowed : this.dropNotAllowed
26361 notifyOut : function(dd, e, data)
26363 this.fireEvent('out', dd, e, data);
26364 if(this.overClass){
26365 this.el.removeClass(this.overClass);
26372 notifyDrop : function(dd, e, data)
26374 this.success = false;
26375 this.fireEvent('drop', dd, e, data);
26376 return this.success;
26380 * Ext JS Library 1.1.1
26381 * Copyright(c) 2006-2007, Ext JS, LLC.
26383 * Originally Released Under LGPL - original licence link has changed is not relivant.
26386 * <script type="text/javascript">
26391 * @class Roo.dd.DragZone
26392 * @extends Roo.dd.DragSource
26393 * This class provides a container DD instance that proxies for multiple child node sources.<br />
26394 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
26396 * @param {String/HTMLElement/Element} el The container element
26397 * @param {Object} config
26399 Roo.dd.DragZone = function(el, config){
26400 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
26401 if(this.containerScroll){
26402 Roo.dd.ScrollManager.register(this.el);
26406 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
26408 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
26409 * for auto scrolling during drag operations.
26412 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
26413 * method after a failed drop (defaults to "c3daf9" - light blue)
26417 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
26418 * for a valid target to drag based on the mouse down. Override this method
26419 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
26420 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
26421 * @param {EventObject} e The mouse down event
26422 * @return {Object} The dragData
26424 getDragData : function(e){
26425 return Roo.dd.Registry.getHandleFromEvent(e);
26429 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
26430 * this.dragData.ddel
26431 * @param {Number} x The x position of the click on the dragged object
26432 * @param {Number} y The y position of the click on the dragged object
26433 * @return {Boolean} true to continue the drag, false to cancel
26435 onInitDrag : function(x, y){
26436 this.proxy.update(this.dragData.ddel.cloneNode(true));
26437 this.onStartDrag(x, y);
26442 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
26444 afterRepair : function(){
26446 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
26448 this.dragging = false;
26452 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
26453 * the XY of this.dragData.ddel
26454 * @param {EventObject} e The mouse up event
26455 * @return {Array} The xy location (e.g. [100, 200])
26457 getRepairXY : function(e){
26458 return Roo.Element.fly(this.dragData.ddel).getXY();
26462 * Ext JS Library 1.1.1
26463 * Copyright(c) 2006-2007, Ext JS, LLC.
26465 * Originally Released Under LGPL - original licence link has changed is not relivant.
26468 * <script type="text/javascript">
26471 * @class Roo.dd.DropZone
26472 * @extends Roo.dd.DropTarget
26473 * This class provides a container DD instance that proxies for multiple child node targets.<br />
26474 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
26476 * @param {String/HTMLElement/Element} el The container element
26477 * @param {Object} config
26479 Roo.dd.DropZone = function(el, config){
26480 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
26483 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
26485 * Returns a custom data object associated with the DOM node that is the target of the event. By default
26486 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
26487 * provide your own custom lookup.
26488 * @param {Event} e The event
26489 * @return {Object} data The custom data
26491 getTargetFromEvent : function(e){
26492 return Roo.dd.Registry.getTargetFromEvent(e);
26496 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
26497 * that it has registered. This method has no default implementation and should be overridden to provide
26498 * node-specific processing if necessary.
26499 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
26500 * {@link #getTargetFromEvent} for this node)
26501 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
26502 * @param {Event} e The event
26503 * @param {Object} data An object containing arbitrary data supplied by the drag source
26505 onNodeEnter : function(n, dd, e, data){
26510 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
26511 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
26512 * overridden to provide the proper feedback.
26513 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
26514 * {@link #getTargetFromEvent} for this node)
26515 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
26516 * @param {Event} e The event
26517 * @param {Object} data An object containing arbitrary data supplied by the drag source
26518 * @return {String} status The CSS class that communicates the drop status back to the source so that the
26519 * underlying {@link Roo.dd.StatusProxy} can be updated
26521 onNodeOver : function(n, dd, e, data){
26522 return this.dropAllowed;
26526 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
26527 * the drop node without dropping. This method has no default implementation and should be overridden to provide
26528 * node-specific processing if necessary.
26529 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
26530 * {@link #getTargetFromEvent} for this node)
26531 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
26532 * @param {Event} e The event
26533 * @param {Object} data An object containing arbitrary data supplied by the drag source
26535 onNodeOut : function(n, dd, e, data){
26540 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
26541 * the drop node. The default implementation returns false, so it should be overridden to provide the
26542 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
26543 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
26544 * {@link #getTargetFromEvent} for this node)
26545 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
26546 * @param {Event} e The event
26547 * @param {Object} data An object containing arbitrary data supplied by the drag source
26548 * @return {Boolean} True if the drop was valid, else false
26550 onNodeDrop : function(n, dd, e, data){
26555 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
26556 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
26557 * it should be overridden to provide the proper feedback if necessary.
26558 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
26559 * @param {Event} e The event
26560 * @param {Object} data An object containing arbitrary data supplied by the drag source
26561 * @return {String} status The CSS class that communicates the drop status back to the source so that the
26562 * underlying {@link Roo.dd.StatusProxy} can be updated
26564 onContainerOver : function(dd, e, data){
26565 return this.dropNotAllowed;
26569 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
26570 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
26571 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
26572 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
26573 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
26574 * @param {Event} e The event
26575 * @param {Object} data An object containing arbitrary data supplied by the drag source
26576 * @return {Boolean} True if the drop was valid, else false
26578 onContainerDrop : function(dd, e, data){
26583 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
26584 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
26585 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
26586 * you should override this method and provide a custom implementation.
26587 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
26588 * @param {Event} e The event
26589 * @param {Object} data An object containing arbitrary data supplied by the drag source
26590 * @return {String} status The CSS class that communicates the drop status back to the source so that the
26591 * underlying {@link Roo.dd.StatusProxy} can be updated
26593 notifyEnter : function(dd, e, data){
26594 return this.dropNotAllowed;
26598 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
26599 * This method will be called on every mouse movement while the drag source is over the drop zone.
26600 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
26601 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
26602 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
26603 * registered node, it will call {@link #onContainerOver}.
26604 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
26605 * @param {Event} e The event
26606 * @param {Object} data An object containing arbitrary data supplied by the drag source
26607 * @return {String} status The CSS class that communicates the drop status back to the source so that the
26608 * underlying {@link Roo.dd.StatusProxy} can be updated
26610 notifyOver : function(dd, e, data){
26611 var n = this.getTargetFromEvent(e);
26612 if(!n){ // not over valid drop target
26613 if(this.lastOverNode){
26614 this.onNodeOut(this.lastOverNode, dd, e, data);
26615 this.lastOverNode = null;
26617 return this.onContainerOver(dd, e, data);
26619 if(this.lastOverNode != n){
26620 if(this.lastOverNode){
26621 this.onNodeOut(this.lastOverNode, dd, e, data);
26623 this.onNodeEnter(n, dd, e, data);
26624 this.lastOverNode = n;
26626 return this.onNodeOver(n, dd, e, data);
26630 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
26631 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
26632 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
26633 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
26634 * @param {Event} e The event
26635 * @param {Object} data An object containing arbitrary data supplied by the drag zone
26637 notifyOut : function(dd, e, data){
26638 if(this.lastOverNode){
26639 this.onNodeOut(this.lastOverNode, dd, e, data);
26640 this.lastOverNode = null;
26645 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
26646 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
26647 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
26648 * otherwise it will call {@link #onContainerDrop}.
26649 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
26650 * @param {Event} e The event
26651 * @param {Object} data An object containing arbitrary data supplied by the drag source
26652 * @return {Boolean} True if the drop was valid, else false
26654 notifyDrop : function(dd, e, data){
26655 if(this.lastOverNode){
26656 this.onNodeOut(this.lastOverNode, dd, e, data);
26657 this.lastOverNode = null;
26659 var n = this.getTargetFromEvent(e);
26661 this.onNodeDrop(n, dd, e, data) :
26662 this.onContainerDrop(dd, e, data);
26666 triggerCacheRefresh : function(){
26667 Roo.dd.DDM.refreshCache(this.groups);
26671 * Ext JS Library 1.1.1
26672 * Copyright(c) 2006-2007, Ext JS, LLC.
26674 * Originally Released Under LGPL - original licence link has changed is not relivant.
26677 * <script type="text/javascript">
26682 * @class Roo.data.SortTypes
26684 * Defines the default sorting (casting?) comparison functions used when sorting data.
26686 Roo.data.SortTypes = {
26688 * Default sort that does nothing
26689 * @param {Mixed} s The value being converted
26690 * @return {Mixed} The comparison value
26692 none : function(s){
26697 * The regular expression used to strip tags
26701 stripTagsRE : /<\/?[^>]+>/gi,
26704 * Strips all HTML tags to sort on text only
26705 * @param {Mixed} s The value being converted
26706 * @return {String} The comparison value
26708 asText : function(s){
26709 return String(s).replace(this.stripTagsRE, "");
26713 * Strips all HTML tags to sort on text only - Case insensitive
26714 * @param {Mixed} s The value being converted
26715 * @return {String} The comparison value
26717 asUCText : function(s){
26718 return String(s).toUpperCase().replace(this.stripTagsRE, "");
26722 * Case insensitive string
26723 * @param {Mixed} s The value being converted
26724 * @return {String} The comparison value
26726 asUCString : function(s) {
26727 return String(s).toUpperCase();
26732 * @param {Mixed} s The value being converted
26733 * @return {Number} The comparison value
26735 asDate : function(s) {
26739 if(s instanceof Date){
26740 return s.getTime();
26742 return Date.parse(String(s));
26747 * @param {Mixed} s The value being converted
26748 * @return {Float} The comparison value
26750 asFloat : function(s) {
26751 var val = parseFloat(String(s).replace(/,/g, ""));
26760 * @param {Mixed} s The value being converted
26761 * @return {Number} The comparison value
26763 asInt : function(s) {
26764 var val = parseInt(String(s).replace(/,/g, ""));
26772 * Ext JS Library 1.1.1
26773 * Copyright(c) 2006-2007, Ext JS, LLC.
26775 * Originally Released Under LGPL - original licence link has changed is not relivant.
26778 * <script type="text/javascript">
26782 * @class Roo.data.Record
26783 * Instances of this class encapsulate both record <em>definition</em> information, and record
26784 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
26785 * to access Records cached in an {@link Roo.data.Store} object.<br>
26787 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
26788 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
26791 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
26793 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
26794 * {@link #create}. The parameters are the same.
26795 * @param {Array} data An associative Array of data values keyed by the field name.
26796 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
26797 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
26798 * not specified an integer id is generated.
26800 Roo.data.Record = function(data, id){
26801 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
26806 * Generate a constructor for a specific record layout.
26807 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
26808 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
26809 * Each field definition object may contain the following properties: <ul>
26810 * <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,
26811 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
26812 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
26813 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
26814 * is being used, then this is a string containing the javascript expression to reference the data relative to
26815 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
26816 * to the data item relative to the record element. If the mapping expression is the same as the field name,
26817 * this may be omitted.</p></li>
26818 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
26819 * <ul><li>auto (Default, implies no conversion)</li>
26824 * <li>date</li></ul></p></li>
26825 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
26826 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
26827 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
26828 * by the Reader into an object that will be stored in the Record. It is passed the
26829 * following parameters:<ul>
26830 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
26832 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
26834 * <br>usage:<br><pre><code>
26835 var TopicRecord = Roo.data.Record.create(
26836 {name: 'title', mapping: 'topic_title'},
26837 {name: 'author', mapping: 'username'},
26838 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
26839 {name: 'lastPost', mapping: 'post_time', type: 'date'},
26840 {name: 'lastPoster', mapping: 'user2'},
26841 {name: 'excerpt', mapping: 'post_text'}
26844 var myNewRecord = new TopicRecord({
26845 title: 'Do my job please',
26848 lastPost: new Date(),
26849 lastPoster: 'Animal',
26850 excerpt: 'No way dude!'
26852 myStore.add(myNewRecord);
26857 Roo.data.Record.create = function(o){
26858 var f = function(){
26859 f.superclass.constructor.apply(this, arguments);
26861 Roo.extend(f, Roo.data.Record);
26862 var p = f.prototype;
26863 p.fields = new Roo.util.MixedCollection(false, function(field){
26866 for(var i = 0, len = o.length; i < len; i++){
26867 p.fields.add(new Roo.data.Field(o[i]));
26869 f.getField = function(name){
26870 return p.fields.get(name);
26875 Roo.data.Record.AUTO_ID = 1000;
26876 Roo.data.Record.EDIT = 'edit';
26877 Roo.data.Record.REJECT = 'reject';
26878 Roo.data.Record.COMMIT = 'commit';
26880 Roo.data.Record.prototype = {
26882 * Readonly flag - true if this record has been modified.
26891 join : function(store){
26892 this.store = store;
26896 * Set the named field to the specified value.
26897 * @param {String} name The name of the field to set.
26898 * @param {Object} value The value to set the field to.
26900 set : function(name, value){
26901 if(this.data[name] == value){
26905 if(!this.modified){
26906 this.modified = {};
26908 if(typeof this.modified[name] == 'undefined'){
26909 this.modified[name] = this.data[name];
26911 this.data[name] = value;
26912 if(!this.editing && this.store){
26913 this.store.afterEdit(this);
26918 * Get the value of the named field.
26919 * @param {String} name The name of the field to get the value of.
26920 * @return {Object} The value of the field.
26922 get : function(name){
26923 return this.data[name];
26927 beginEdit : function(){
26928 this.editing = true;
26929 this.modified = {};
26933 cancelEdit : function(){
26934 this.editing = false;
26935 delete this.modified;
26939 endEdit : function(){
26940 this.editing = false;
26941 if(this.dirty && this.store){
26942 this.store.afterEdit(this);
26947 * Usually called by the {@link Roo.data.Store} which owns the Record.
26948 * Rejects all changes made to the Record since either creation, or the last commit operation.
26949 * Modified fields are reverted to their original values.
26951 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
26952 * of reject operations.
26954 reject : function(){
26955 var m = this.modified;
26957 if(typeof m[n] != "function"){
26958 this.data[n] = m[n];
26961 this.dirty = false;
26962 delete this.modified;
26963 this.editing = false;
26965 this.store.afterReject(this);
26970 * Usually called by the {@link Roo.data.Store} which owns the Record.
26971 * Commits all changes made to the Record since either creation, or the last commit operation.
26973 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
26974 * of commit operations.
26976 commit : function(){
26977 this.dirty = false;
26978 delete this.modified;
26979 this.editing = false;
26981 this.store.afterCommit(this);
26986 hasError : function(){
26987 return this.error != null;
26991 clearError : function(){
26996 * Creates a copy of this record.
26997 * @param {String} id (optional) A new record id if you don't want to use this record's id
27000 copy : function(newId) {
27001 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
27005 * Ext JS Library 1.1.1
27006 * Copyright(c) 2006-2007, Ext JS, LLC.
27008 * Originally Released Under LGPL - original licence link has changed is not relivant.
27011 * <script type="text/javascript">
27017 * @class Roo.data.Store
27018 * @extends Roo.util.Observable
27019 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
27020 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
27022 * 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
27023 * has no knowledge of the format of the data returned by the Proxy.<br>
27025 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
27026 * instances from the data object. These records are cached and made available through accessor functions.
27028 * Creates a new Store.
27029 * @param {Object} config A config object containing the objects needed for the Store to access data,
27030 * and read the data into Records.
27032 Roo.data.Store = function(config){
27033 this.data = new Roo.util.MixedCollection(false);
27034 this.data.getKey = function(o){
27037 this.baseParams = {};
27039 this.paramNames = {
27044 "multisort" : "_multisort"
27047 if(config && config.data){
27048 this.inlineData = config.data;
27049 delete config.data;
27052 Roo.apply(this, config);
27054 if(this.reader){ // reader passed
27055 this.reader = Roo.factory(this.reader, Roo.data);
27056 this.reader.xmodule = this.xmodule || false;
27057 if(!this.recordType){
27058 this.recordType = this.reader.recordType;
27060 if(this.reader.onMetaChange){
27061 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
27065 if(this.recordType){
27066 this.fields = this.recordType.prototype.fields;
27068 this.modified = [];
27072 * @event datachanged
27073 * Fires when the data cache has changed, and a widget which is using this Store
27074 * as a Record cache should refresh its view.
27075 * @param {Store} this
27077 datachanged : true,
27079 * @event metachange
27080 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
27081 * @param {Store} this
27082 * @param {Object} meta The JSON metadata
27087 * Fires when Records have been added to the Store
27088 * @param {Store} this
27089 * @param {Roo.data.Record[]} records The array of Records added
27090 * @param {Number} index The index at which the record(s) were added
27095 * Fires when a Record has been removed from the Store
27096 * @param {Store} this
27097 * @param {Roo.data.Record} record The Record that was removed
27098 * @param {Number} index The index at which the record was removed
27103 * Fires when a Record has been updated
27104 * @param {Store} this
27105 * @param {Roo.data.Record} record The Record that was updated
27106 * @param {String} operation The update operation being performed. Value may be one of:
27108 Roo.data.Record.EDIT
27109 Roo.data.Record.REJECT
27110 Roo.data.Record.COMMIT
27116 * Fires when the data cache has been cleared.
27117 * @param {Store} this
27121 * @event beforeload
27122 * Fires before a request is made for a new data object. If the beforeload handler returns false
27123 * the load action will be canceled.
27124 * @param {Store} this
27125 * @param {Object} options The loading options that were specified (see {@link #load} for details)
27129 * @event beforeloadadd
27130 * Fires after a new set of Records has been loaded.
27131 * @param {Store} this
27132 * @param {Roo.data.Record[]} records The Records that were loaded
27133 * @param {Object} options The loading options that were specified (see {@link #load} for details)
27135 beforeloadadd : true,
27138 * Fires after a new set of Records has been loaded, before they are added to the store.
27139 * @param {Store} this
27140 * @param {Roo.data.Record[]} records The Records that were loaded
27141 * @param {Object} options The loading options that were specified (see {@link #load} for details)
27142 * @params {Object} return from reader
27146 * @event loadexception
27147 * Fires if an exception occurs in the Proxy during loading.
27148 * Called with the signature of the Proxy's "loadexception" event.
27149 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
27152 * @param {Object} return from JsonData.reader() - success, totalRecords, records
27153 * @param {Object} load options
27154 * @param {Object} jsonData from your request (normally this contains the Exception)
27156 loadexception : true
27160 this.proxy = Roo.factory(this.proxy, Roo.data);
27161 this.proxy.xmodule = this.xmodule || false;
27162 this.relayEvents(this.proxy, ["loadexception"]);
27164 this.sortToggle = {};
27165 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
27167 Roo.data.Store.superclass.constructor.call(this);
27169 if(this.inlineData){
27170 this.loadData(this.inlineData);
27171 delete this.inlineData;
27175 Roo.extend(Roo.data.Store, Roo.util.Observable, {
27177 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
27178 * without a remote query - used by combo/forms at present.
27182 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
27185 * @cfg {Array} data Inline data to be loaded when the store is initialized.
27188 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
27189 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
27192 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
27193 * on any HTTP request
27196 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
27199 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
27203 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
27204 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
27206 remoteSort : false,
27209 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
27210 * loaded or when a record is removed. (defaults to false).
27212 pruneModifiedRecords : false,
27215 lastOptions : null,
27218 * Add Records to the Store and fires the add event.
27219 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
27221 add : function(records){
27222 records = [].concat(records);
27223 for(var i = 0, len = records.length; i < len; i++){
27224 records[i].join(this);
27226 var index = this.data.length;
27227 this.data.addAll(records);
27228 this.fireEvent("add", this, records, index);
27232 * Remove a Record from the Store and fires the remove event.
27233 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
27235 remove : function(record){
27236 var index = this.data.indexOf(record);
27237 this.data.removeAt(index);
27238 if(this.pruneModifiedRecords){
27239 this.modified.remove(record);
27241 this.fireEvent("remove", this, record, index);
27245 * Remove all Records from the Store and fires the clear event.
27247 removeAll : function(){
27249 if(this.pruneModifiedRecords){
27250 this.modified = [];
27252 this.fireEvent("clear", this);
27256 * Inserts Records to the Store at the given index and fires the add event.
27257 * @param {Number} index The start index at which to insert the passed Records.
27258 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
27260 insert : function(index, records){
27261 records = [].concat(records);
27262 for(var i = 0, len = records.length; i < len; i++){
27263 this.data.insert(index, records[i]);
27264 records[i].join(this);
27266 this.fireEvent("add", this, records, index);
27270 * Get the index within the cache of the passed Record.
27271 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
27272 * @return {Number} The index of the passed Record. Returns -1 if not found.
27274 indexOf : function(record){
27275 return this.data.indexOf(record);
27279 * Get the index within the cache of the Record with the passed id.
27280 * @param {String} id The id of the Record to find.
27281 * @return {Number} The index of the Record. Returns -1 if not found.
27283 indexOfId : function(id){
27284 return this.data.indexOfKey(id);
27288 * Get the Record with the specified id.
27289 * @param {String} id The id of the Record to find.
27290 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
27292 getById : function(id){
27293 return this.data.key(id);
27297 * Get the Record at the specified index.
27298 * @param {Number} index The index of the Record to find.
27299 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
27301 getAt : function(index){
27302 return this.data.itemAt(index);
27306 * Returns a range of Records between specified indices.
27307 * @param {Number} startIndex (optional) The starting index (defaults to 0)
27308 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
27309 * @return {Roo.data.Record[]} An array of Records
27311 getRange : function(start, end){
27312 return this.data.getRange(start, end);
27316 storeOptions : function(o){
27317 o = Roo.apply({}, o);
27320 this.lastOptions = o;
27324 * Loads the Record cache from the configured Proxy using the configured Reader.
27326 * If using remote paging, then the first load call must specify the <em>start</em>
27327 * and <em>limit</em> properties in the options.params property to establish the initial
27328 * position within the dataset, and the number of Records to cache on each read from the Proxy.
27330 * <strong>It is important to note that for remote data sources, loading is asynchronous,
27331 * and this call will return before the new data has been loaded. Perform any post-processing
27332 * in a callback function, or in a "load" event handler.</strong>
27334 * @param {Object} options An object containing properties which control loading options:<ul>
27335 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
27336 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
27337 * passed the following arguments:<ul>
27338 * <li>r : Roo.data.Record[]</li>
27339 * <li>options: Options object from the load call</li>
27340 * <li>success: Boolean success indicator</li></ul></li>
27341 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
27342 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
27345 load : function(options){
27346 options = options || {};
27347 if(this.fireEvent("beforeload", this, options) !== false){
27348 this.storeOptions(options);
27349 var p = Roo.apply(options.params || {}, this.baseParams);
27350 // if meta was not loaded from remote source.. try requesting it.
27351 if (!this.reader.metaFromRemote) {
27352 p._requestMeta = 1;
27354 if(this.sortInfo && this.remoteSort){
27355 var pn = this.paramNames;
27356 p[pn["sort"]] = this.sortInfo.field;
27357 p[pn["dir"]] = this.sortInfo.direction;
27359 if (this.multiSort) {
27360 var pn = this.paramNames;
27361 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
27364 this.proxy.load(p, this.reader, this.loadRecords, this, options);
27369 * Reloads the Record cache from the configured Proxy using the configured Reader and
27370 * the options from the last load operation performed.
27371 * @param {Object} options (optional) An object containing properties which may override the options
27372 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
27373 * the most recently used options are reused).
27375 reload : function(options){
27376 this.load(Roo.applyIf(options||{}, this.lastOptions));
27380 // Called as a callback by the Reader during a load operation.
27381 loadRecords : function(o, options, success){
27382 if(!o || success === false){
27383 if(success !== false){
27384 this.fireEvent("load", this, [], options, o);
27386 if(options.callback){
27387 options.callback.call(options.scope || this, [], options, false);
27391 // if data returned failure - throw an exception.
27392 if (o.success === false) {
27393 // show a message if no listener is registered.
27394 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
27395 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
27397 // loadmask wil be hooked into this..
27398 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
27401 var r = o.records, t = o.totalRecords || r.length;
27403 this.fireEvent("beforeloadadd", this, r, options, o);
27405 if(!options || options.add !== true){
27406 if(this.pruneModifiedRecords){
27407 this.modified = [];
27409 for(var i = 0, len = r.length; i < len; i++){
27413 this.data = this.snapshot;
27414 delete this.snapshot;
27417 this.data.addAll(r);
27418 this.totalLength = t;
27420 this.fireEvent("datachanged", this);
27422 this.totalLength = Math.max(t, this.data.length+r.length);
27425 this.fireEvent("load", this, r, options, o);
27426 if(options.callback){
27427 options.callback.call(options.scope || this, r, options, true);
27433 * Loads data from a passed data block. A Reader which understands the format of the data
27434 * must have been configured in the constructor.
27435 * @param {Object} data The data block from which to read the Records. The format of the data expected
27436 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
27437 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
27439 loadData : function(o, append){
27440 var r = this.reader.readRecords(o);
27441 this.loadRecords(r, {add: append}, true);
27445 * Gets the number of cached records.
27447 * <em>If using paging, this may not be the total size of the dataset. If the data object
27448 * used by the Reader contains the dataset size, then the getTotalCount() function returns
27449 * the data set size</em>
27451 getCount : function(){
27452 return this.data.length || 0;
27456 * Gets the total number of records in the dataset as returned by the server.
27458 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
27459 * the dataset size</em>
27461 getTotalCount : function(){
27462 return this.totalLength || 0;
27466 * Returns the sort state of the Store as an object with two properties:
27468 field {String} The name of the field by which the Records are sorted
27469 direction {String} The sort order, "ASC" or "DESC"
27472 getSortState : function(){
27473 return this.sortInfo;
27477 applySort : function(){
27478 if(this.sortInfo && !this.remoteSort){
27479 var s = this.sortInfo, f = s.field;
27480 var st = this.fields.get(f).sortType;
27481 var fn = function(r1, r2){
27482 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
27483 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
27485 this.data.sort(s.direction, fn);
27486 if(this.snapshot && this.snapshot != this.data){
27487 this.snapshot.sort(s.direction, fn);
27493 * Sets the default sort column and order to be used by the next load operation.
27494 * @param {String} fieldName The name of the field to sort by.
27495 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
27497 setDefaultSort : function(field, dir){
27498 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
27502 * Sort the Records.
27503 * If remote sorting is used, the sort is performed on the server, and the cache is
27504 * reloaded. If local sorting is used, the cache is sorted internally.
27505 * @param {String} fieldName The name of the field to sort by.
27506 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
27508 sort : function(fieldName, dir){
27509 var f = this.fields.get(fieldName);
27511 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
27513 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
27514 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
27519 this.sortToggle[f.name] = dir;
27520 this.sortInfo = {field: f.name, direction: dir};
27521 if(!this.remoteSort){
27523 this.fireEvent("datachanged", this);
27525 this.load(this.lastOptions);
27530 * Calls the specified function for each of the Records in the cache.
27531 * @param {Function} fn The function to call. The Record is passed as the first parameter.
27532 * Returning <em>false</em> aborts and exits the iteration.
27533 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
27535 each : function(fn, scope){
27536 this.data.each(fn, scope);
27540 * Gets all records modified since the last commit. Modified records are persisted across load operations
27541 * (e.g., during paging).
27542 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
27544 getModifiedRecords : function(){
27545 return this.modified;
27549 createFilterFn : function(property, value, anyMatch){
27550 if(!value.exec){ // not a regex
27551 value = String(value);
27552 if(value.length == 0){
27555 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
27557 return function(r){
27558 return value.test(r.data[property]);
27563 * Sums the value of <i>property</i> for each record between start and end and returns the result.
27564 * @param {String} property A field on your records
27565 * @param {Number} start The record index to start at (defaults to 0)
27566 * @param {Number} end The last record index to include (defaults to length - 1)
27567 * @return {Number} The sum
27569 sum : function(property, start, end){
27570 var rs = this.data.items, v = 0;
27571 start = start || 0;
27572 end = (end || end === 0) ? end : rs.length-1;
27574 for(var i = start; i <= end; i++){
27575 v += (rs[i].data[property] || 0);
27581 * Filter the records by a specified property.
27582 * @param {String} field A field on your records
27583 * @param {String/RegExp} value Either a string that the field
27584 * should start with or a RegExp to test against the field
27585 * @param {Boolean} anyMatch True to match any part not just the beginning
27587 filter : function(property, value, anyMatch){
27588 var fn = this.createFilterFn(property, value, anyMatch);
27589 return fn ? this.filterBy(fn) : this.clearFilter();
27593 * Filter by a function. The specified function will be called with each
27594 * record in this data source. If the function returns true the record is included,
27595 * otherwise it is filtered.
27596 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
27597 * @param {Object} scope (optional) The scope of the function (defaults to this)
27599 filterBy : function(fn, scope){
27600 this.snapshot = this.snapshot || this.data;
27601 this.data = this.queryBy(fn, scope||this);
27602 this.fireEvent("datachanged", this);
27606 * Query the records by a specified property.
27607 * @param {String} field A field on your records
27608 * @param {String/RegExp} value Either a string that the field
27609 * should start with or a RegExp to test against the field
27610 * @param {Boolean} anyMatch True to match any part not just the beginning
27611 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
27613 query : function(property, value, anyMatch){
27614 var fn = this.createFilterFn(property, value, anyMatch);
27615 return fn ? this.queryBy(fn) : this.data.clone();
27619 * Query by a function. The specified function will be called with each
27620 * record in this data source. If the function returns true the record is included
27622 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
27623 * @param {Object} scope (optional) The scope of the function (defaults to this)
27624 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
27626 queryBy : function(fn, scope){
27627 var data = this.snapshot || this.data;
27628 return data.filterBy(fn, scope||this);
27632 * Collects unique values for a particular dataIndex from this store.
27633 * @param {String} dataIndex The property to collect
27634 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
27635 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
27636 * @return {Array} An array of the unique values
27638 collect : function(dataIndex, allowNull, bypassFilter){
27639 var d = (bypassFilter === true && this.snapshot) ?
27640 this.snapshot.items : this.data.items;
27641 var v, sv, r = [], l = {};
27642 for(var i = 0, len = d.length; i < len; i++){
27643 v = d[i].data[dataIndex];
27645 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
27654 * Revert to a view of the Record cache with no filtering applied.
27655 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
27657 clearFilter : function(suppressEvent){
27658 if(this.snapshot && this.snapshot != this.data){
27659 this.data = this.snapshot;
27660 delete this.snapshot;
27661 if(suppressEvent !== true){
27662 this.fireEvent("datachanged", this);
27668 afterEdit : function(record){
27669 if(this.modified.indexOf(record) == -1){
27670 this.modified.push(record);
27672 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
27676 afterReject : function(record){
27677 this.modified.remove(record);
27678 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
27682 afterCommit : function(record){
27683 this.modified.remove(record);
27684 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
27688 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
27689 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
27691 commitChanges : function(){
27692 var m = this.modified.slice(0);
27693 this.modified = [];
27694 for(var i = 0, len = m.length; i < len; i++){
27700 * Cancel outstanding changes on all changed records.
27702 rejectChanges : function(){
27703 var m = this.modified.slice(0);
27704 this.modified = [];
27705 for(var i = 0, len = m.length; i < len; i++){
27710 onMetaChange : function(meta, rtype, o){
27711 this.recordType = rtype;
27712 this.fields = rtype.prototype.fields;
27713 delete this.snapshot;
27714 this.sortInfo = meta.sortInfo || this.sortInfo;
27715 this.modified = [];
27716 this.fireEvent('metachange', this, this.reader.meta);
27719 moveIndex : function(data, type)
27721 var index = this.indexOf(data);
27723 var newIndex = index + type;
27727 this.insert(newIndex, data);
27732 * Ext JS Library 1.1.1
27733 * Copyright(c) 2006-2007, Ext JS, LLC.
27735 * Originally Released Under LGPL - original licence link has changed is not relivant.
27738 * <script type="text/javascript">
27742 * @class Roo.data.SimpleStore
27743 * @extends Roo.data.Store
27744 * Small helper class to make creating Stores from Array data easier.
27745 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
27746 * @cfg {Array} fields An array of field definition objects, or field name strings.
27747 * @cfg {Array} data The multi-dimensional array of data
27749 * @param {Object} config
27751 Roo.data.SimpleStore = function(config){
27752 Roo.data.SimpleStore.superclass.constructor.call(this, {
27754 reader: new Roo.data.ArrayReader({
27757 Roo.data.Record.create(config.fields)
27759 proxy : new Roo.data.MemoryProxy(config.data)
27763 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
27765 * Ext JS Library 1.1.1
27766 * Copyright(c) 2006-2007, Ext JS, LLC.
27768 * Originally Released Under LGPL - original licence link has changed is not relivant.
27771 * <script type="text/javascript">
27776 * @extends Roo.data.Store
27777 * @class Roo.data.JsonStore
27778 * Small helper class to make creating Stores for JSON data easier. <br/>
27780 var store = new Roo.data.JsonStore({
27781 url: 'get-images.php',
27783 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
27786 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
27787 * JsonReader and HttpProxy (unless inline data is provided).</b>
27788 * @cfg {Array} fields An array of field definition objects, or field name strings.
27790 * @param {Object} config
27792 Roo.data.JsonStore = function(c){
27793 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
27794 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
27795 reader: new Roo.data.JsonReader(c, c.fields)
27798 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
27800 * Ext JS Library 1.1.1
27801 * Copyright(c) 2006-2007, Ext JS, LLC.
27803 * Originally Released Under LGPL - original licence link has changed is not relivant.
27806 * <script type="text/javascript">
27810 Roo.data.Field = function(config){
27811 if(typeof config == "string"){
27812 config = {name: config};
27814 Roo.apply(this, config);
27817 this.type = "auto";
27820 var st = Roo.data.SortTypes;
27821 // named sortTypes are supported, here we look them up
27822 if(typeof this.sortType == "string"){
27823 this.sortType = st[this.sortType];
27826 // set default sortType for strings and dates
27827 if(!this.sortType){
27830 this.sortType = st.asUCString;
27833 this.sortType = st.asDate;
27836 this.sortType = st.none;
27841 var stripRe = /[\$,%]/g;
27843 // prebuilt conversion function for this field, instead of
27844 // switching every time we're reading a value
27846 var cv, dateFormat = this.dateFormat;
27851 cv = function(v){ return v; };
27854 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
27858 return v !== undefined && v !== null && v !== '' ?
27859 parseInt(String(v).replace(stripRe, ""), 10) : '';
27864 return v !== undefined && v !== null && v !== '' ?
27865 parseFloat(String(v).replace(stripRe, ""), 10) : '';
27870 cv = function(v){ return v === true || v === "true" || v == 1; };
27877 if(v instanceof Date){
27881 if(dateFormat == "timestamp"){
27882 return new Date(v*1000);
27884 return Date.parseDate(v, dateFormat);
27886 var parsed = Date.parse(v);
27887 return parsed ? new Date(parsed) : null;
27896 Roo.data.Field.prototype = {
27904 * Ext JS Library 1.1.1
27905 * Copyright(c) 2006-2007, Ext JS, LLC.
27907 * Originally Released Under LGPL - original licence link has changed is not relivant.
27910 * <script type="text/javascript">
27913 // Base class for reading structured data from a data source. This class is intended to be
27914 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
27917 * @class Roo.data.DataReader
27918 * Base class for reading structured data from a data source. This class is intended to be
27919 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
27922 Roo.data.DataReader = function(meta, recordType){
27926 this.recordType = recordType instanceof Array ?
27927 Roo.data.Record.create(recordType) : recordType;
27930 Roo.data.DataReader.prototype = {
27932 * Create an empty record
27933 * @param {Object} data (optional) - overlay some values
27934 * @return {Roo.data.Record} record created.
27936 newRow : function(d) {
27938 this.recordType.prototype.fields.each(function(c) {
27940 case 'int' : da[c.name] = 0; break;
27941 case 'date' : da[c.name] = new Date(); break;
27942 case 'float' : da[c.name] = 0.0; break;
27943 case 'boolean' : da[c.name] = false; break;
27944 default : da[c.name] = ""; break;
27948 return new this.recordType(Roo.apply(da, d));
27953 * Ext JS Library 1.1.1
27954 * Copyright(c) 2006-2007, Ext JS, LLC.
27956 * Originally Released Under LGPL - original licence link has changed is not relivant.
27959 * <script type="text/javascript">
27963 * @class Roo.data.DataProxy
27964 * @extends Roo.data.Observable
27965 * This class is an abstract base class for implementations which provide retrieval of
27966 * unformatted data objects.<br>
27968 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
27969 * (of the appropriate type which knows how to parse the data object) to provide a block of
27970 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
27972 * Custom implementations must implement the load method as described in
27973 * {@link Roo.data.HttpProxy#load}.
27975 Roo.data.DataProxy = function(){
27978 * @event beforeload
27979 * Fires before a network request is made to retrieve a data object.
27980 * @param {Object} This DataProxy object.
27981 * @param {Object} params The params parameter to the load function.
27986 * Fires before the load method's callback is called.
27987 * @param {Object} This DataProxy object.
27988 * @param {Object} o The data object.
27989 * @param {Object} arg The callback argument object passed to the load function.
27993 * @event loadexception
27994 * Fires if an Exception occurs during data retrieval.
27995 * @param {Object} This DataProxy object.
27996 * @param {Object} o The data object.
27997 * @param {Object} arg The callback argument object passed to the load function.
27998 * @param {Object} e The Exception.
28000 loadexception : true
28002 Roo.data.DataProxy.superclass.constructor.call(this);
28005 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
28008 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
28012 * Ext JS Library 1.1.1
28013 * Copyright(c) 2006-2007, Ext JS, LLC.
28015 * Originally Released Under LGPL - original licence link has changed is not relivant.
28018 * <script type="text/javascript">
28021 * @class Roo.data.MemoryProxy
28022 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
28023 * to the Reader when its load method is called.
28025 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
28027 Roo.data.MemoryProxy = function(data){
28031 Roo.data.MemoryProxy.superclass.constructor.call(this);
28035 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
28037 * Load data from the requested source (in this case an in-memory
28038 * data object passed to the constructor), read the data object into
28039 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
28040 * process that block using the passed callback.
28041 * @param {Object} params This parameter is not used by the MemoryProxy class.
28042 * @param {Roo.data.DataReader} reader The Reader object which converts the data
28043 * object into a block of Roo.data.Records.
28044 * @param {Function} callback The function into which to pass the block of Roo.data.records.
28045 * The function must be passed <ul>
28046 * <li>The Record block object</li>
28047 * <li>The "arg" argument from the load function</li>
28048 * <li>A boolean success indicator</li>
28050 * @param {Object} scope The scope in which to call the callback
28051 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
28053 load : function(params, reader, callback, scope, arg){
28054 params = params || {};
28057 result = reader.readRecords(this.data);
28059 this.fireEvent("loadexception", this, arg, null, e);
28060 callback.call(scope, null, arg, false);
28063 callback.call(scope, result, arg, true);
28067 update : function(params, records){
28072 * Ext JS Library 1.1.1
28073 * Copyright(c) 2006-2007, Ext JS, LLC.
28075 * Originally Released Under LGPL - original licence link has changed is not relivant.
28078 * <script type="text/javascript">
28081 * @class Roo.data.HttpProxy
28082 * @extends Roo.data.DataProxy
28083 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
28084 * configured to reference a certain URL.<br><br>
28086 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
28087 * from which the running page was served.<br><br>
28089 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
28091 * Be aware that to enable the browser to parse an XML document, the server must set
28092 * the Content-Type header in the HTTP response to "text/xml".
28094 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
28095 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
28096 * will be used to make the request.
28098 Roo.data.HttpProxy = function(conn){
28099 Roo.data.HttpProxy.superclass.constructor.call(this);
28100 // is conn a conn config or a real conn?
28102 this.useAjax = !conn || !conn.events;
28106 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
28107 // thse are take from connection...
28110 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
28113 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
28114 * extra parameters to each request made by this object. (defaults to undefined)
28117 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
28118 * to each request made by this object. (defaults to undefined)
28121 * @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)
28124 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
28127 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
28133 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
28137 * Return the {@link Roo.data.Connection} object being used by this Proxy.
28138 * @return {Connection} The Connection object. This object may be used to subscribe to events on
28139 * a finer-grained basis than the DataProxy events.
28141 getConnection : function(){
28142 return this.useAjax ? Roo.Ajax : this.conn;
28146 * Load data from the configured {@link Roo.data.Connection}, read the data object into
28147 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
28148 * process that block using the passed callback.
28149 * @param {Object} params An object containing properties which are to be used as HTTP parameters
28150 * for the request to the remote server.
28151 * @param {Roo.data.DataReader} reader The Reader object which converts the data
28152 * object into a block of Roo.data.Records.
28153 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
28154 * The function must be passed <ul>
28155 * <li>The Record block object</li>
28156 * <li>The "arg" argument from the load function</li>
28157 * <li>A boolean success indicator</li>
28159 * @param {Object} scope The scope in which to call the callback
28160 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
28162 load : function(params, reader, callback, scope, arg){
28163 if(this.fireEvent("beforeload", this, params) !== false){
28165 params : params || {},
28167 callback : callback,
28172 callback : this.loadResponse,
28176 Roo.applyIf(o, this.conn);
28177 if(this.activeRequest){
28178 Roo.Ajax.abort(this.activeRequest);
28180 this.activeRequest = Roo.Ajax.request(o);
28182 this.conn.request(o);
28185 callback.call(scope||this, null, arg, false);
28190 loadResponse : function(o, success, response){
28191 delete this.activeRequest;
28193 this.fireEvent("loadexception", this, o, response);
28194 o.request.callback.call(o.request.scope, null, o.request.arg, false);
28199 result = o.reader.read(response);
28201 this.fireEvent("loadexception", this, o, response, e);
28202 o.request.callback.call(o.request.scope, null, o.request.arg, false);
28206 this.fireEvent("load", this, o, o.request.arg);
28207 o.request.callback.call(o.request.scope, result, o.request.arg, true);
28211 update : function(dataSet){
28216 updateResponse : function(dataSet){
28221 * Ext JS Library 1.1.1
28222 * Copyright(c) 2006-2007, Ext JS, LLC.
28224 * Originally Released Under LGPL - original licence link has changed is not relivant.
28227 * <script type="text/javascript">
28231 * @class Roo.data.ScriptTagProxy
28232 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
28233 * other than the originating domain of the running page.<br><br>
28235 * <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
28236 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
28238 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
28239 * source code that is used as the source inside a <script> tag.<br><br>
28241 * In order for the browser to process the returned data, the server must wrap the data object
28242 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
28243 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
28244 * depending on whether the callback name was passed:
28247 boolean scriptTag = false;
28248 String cb = request.getParameter("callback");
28251 response.setContentType("text/javascript");
28253 response.setContentType("application/x-json");
28255 Writer out = response.getWriter();
28257 out.write(cb + "(");
28259 out.print(dataBlock.toJsonString());
28266 * @param {Object} config A configuration object.
28268 Roo.data.ScriptTagProxy = function(config){
28269 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
28270 Roo.apply(this, config);
28271 this.head = document.getElementsByTagName("head")[0];
28274 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
28276 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
28278 * @cfg {String} url The URL from which to request the data object.
28281 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
28285 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
28286 * the server the name of the callback function set up by the load call to process the returned data object.
28287 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
28288 * javascript output which calls this named function passing the data object as its only parameter.
28290 callbackParam : "callback",
28292 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
28293 * name to the request.
28298 * Load data from the configured URL, read the data object into
28299 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
28300 * process that block using the passed callback.
28301 * @param {Object} params An object containing properties which are to be used as HTTP parameters
28302 * for the request to the remote server.
28303 * @param {Roo.data.DataReader} reader The Reader object which converts the data
28304 * object into a block of Roo.data.Records.
28305 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
28306 * The function must be passed <ul>
28307 * <li>The Record block object</li>
28308 * <li>The "arg" argument from the load function</li>
28309 * <li>A boolean success indicator</li>
28311 * @param {Object} scope The scope in which to call the callback
28312 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
28314 load : function(params, reader, callback, scope, arg){
28315 if(this.fireEvent("beforeload", this, params) !== false){
28317 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
28319 var url = this.url;
28320 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
28322 url += "&_dc=" + (new Date().getTime());
28324 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
28327 cb : "stcCallback"+transId,
28328 scriptId : "stcScript"+transId,
28332 callback : callback,
28338 window[trans.cb] = function(o){
28339 conn.handleResponse(o, trans);
28342 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
28344 if(this.autoAbort !== false){
28348 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
28350 var script = document.createElement("script");
28351 script.setAttribute("src", url);
28352 script.setAttribute("type", "text/javascript");
28353 script.setAttribute("id", trans.scriptId);
28354 this.head.appendChild(script);
28356 this.trans = trans;
28358 callback.call(scope||this, null, arg, false);
28363 isLoading : function(){
28364 return this.trans ? true : false;
28368 * Abort the current server request.
28370 abort : function(){
28371 if(this.isLoading()){
28372 this.destroyTrans(this.trans);
28377 destroyTrans : function(trans, isLoaded){
28378 this.head.removeChild(document.getElementById(trans.scriptId));
28379 clearTimeout(trans.timeoutId);
28381 window[trans.cb] = undefined;
28383 delete window[trans.cb];
28386 // if hasn't been loaded, wait for load to remove it to prevent script error
28387 window[trans.cb] = function(){
28388 window[trans.cb] = undefined;
28390 delete window[trans.cb];
28397 handleResponse : function(o, trans){
28398 this.trans = false;
28399 this.destroyTrans(trans, true);
28402 result = trans.reader.readRecords(o);
28404 this.fireEvent("loadexception", this, o, trans.arg, e);
28405 trans.callback.call(trans.scope||window, null, trans.arg, false);
28408 this.fireEvent("load", this, o, trans.arg);
28409 trans.callback.call(trans.scope||window, result, trans.arg, true);
28413 handleFailure : function(trans){
28414 this.trans = false;
28415 this.destroyTrans(trans, false);
28416 this.fireEvent("loadexception", this, null, trans.arg);
28417 trans.callback.call(trans.scope||window, null, trans.arg, false);
28421 * Ext JS Library 1.1.1
28422 * Copyright(c) 2006-2007, Ext JS, LLC.
28424 * Originally Released Under LGPL - original licence link has changed is not relivant.
28427 * <script type="text/javascript">
28431 * @class Roo.data.JsonReader
28432 * @extends Roo.data.DataReader
28433 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
28434 * based on mappings in a provided Roo.data.Record constructor.
28436 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
28437 * in the reply previously.
28442 var RecordDef = Roo.data.Record.create([
28443 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
28444 {name: 'occupation'} // This field will use "occupation" as the mapping.
28446 var myReader = new Roo.data.JsonReader({
28447 totalProperty: "results", // The property which contains the total dataset size (optional)
28448 root: "rows", // The property which contains an Array of row objects
28449 id: "id" // The property within each row object that provides an ID for the record (optional)
28453 * This would consume a JSON file like this:
28455 { 'results': 2, 'rows': [
28456 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
28457 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
28460 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
28461 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
28462 * paged from the remote server.
28463 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
28464 * @cfg {String} root name of the property which contains the Array of row objects.
28465 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
28466 * @cfg {Array} fields Array of field definition objects
28468 * Create a new JsonReader
28469 * @param {Object} meta Metadata configuration options
28470 * @param {Object} recordType Either an Array of field definition objects,
28471 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
28473 Roo.data.JsonReader = function(meta, recordType){
28476 // set some defaults:
28477 Roo.applyIf(meta, {
28478 totalProperty: 'total',
28479 successProperty : 'success',
28484 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
28486 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
28489 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
28490 * Used by Store query builder to append _requestMeta to params.
28493 metaFromRemote : false,
28495 * This method is only used by a DataProxy which has retrieved data from a remote server.
28496 * @param {Object} response The XHR object which contains the JSON data in its responseText.
28497 * @return {Object} data A data block which is used by an Roo.data.Store object as
28498 * a cache of Roo.data.Records.
28500 read : function(response){
28501 var json = response.responseText;
28503 var o = /* eval:var:o */ eval("("+json+")");
28505 throw {message: "JsonReader.read: Json object not found"};
28511 this.metaFromRemote = true;
28512 this.meta = o.metaData;
28513 this.recordType = Roo.data.Record.create(o.metaData.fields);
28514 this.onMetaChange(this.meta, this.recordType, o);
28516 return this.readRecords(o);
28519 // private function a store will implement
28520 onMetaChange : function(meta, recordType, o){
28527 simpleAccess: function(obj, subsc) {
28534 getJsonAccessor: function(){
28536 return function(expr) {
28538 return(re.test(expr))
28539 ? new Function("obj", "return obj." + expr)
28544 return Roo.emptyFn;
28549 * Create a data block containing Roo.data.Records from an XML document.
28550 * @param {Object} o An object which contains an Array of row objects in the property specified
28551 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
28552 * which contains the total size of the dataset.
28553 * @return {Object} data A data block which is used by an Roo.data.Store object as
28554 * a cache of Roo.data.Records.
28556 readRecords : function(o){
28558 * After any data loads, the raw JSON data is available for further custom processing.
28562 var s = this.meta, Record = this.recordType,
28563 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
28565 // Generate extraction functions for the totalProperty, the root, the id, and for each field
28567 if(s.totalProperty) {
28568 this.getTotal = this.getJsonAccessor(s.totalProperty);
28570 if(s.successProperty) {
28571 this.getSuccess = this.getJsonAccessor(s.successProperty);
28573 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
28575 var g = this.getJsonAccessor(s.id);
28576 this.getId = function(rec) {
28578 return (r === undefined || r === "") ? null : r;
28581 this.getId = function(){return null;};
28584 for(var jj = 0; jj < fl; jj++){
28586 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
28587 this.ef[jj] = this.getJsonAccessor(map);
28591 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
28592 if(s.totalProperty){
28593 var vt = parseInt(this.getTotal(o), 10);
28598 if(s.successProperty){
28599 var vs = this.getSuccess(o);
28600 if(vs === false || vs === 'false'){
28605 for(var i = 0; i < c; i++){
28608 var id = this.getId(n);
28609 for(var j = 0; j < fl; j++){
28611 var v = this.ef[j](n);
28613 Roo.log('missing convert for ' + f.name);
28617 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
28619 var record = new Record(values, id);
28621 records[i] = record;
28627 totalRecords : totalRecords
28632 * Ext JS Library 1.1.1
28633 * Copyright(c) 2006-2007, Ext JS, LLC.
28635 * Originally Released Under LGPL - original licence link has changed is not relivant.
28638 * <script type="text/javascript">
28642 * @class Roo.data.XmlReader
28643 * @extends Roo.data.DataReader
28644 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
28645 * based on mappings in a provided Roo.data.Record constructor.<br><br>
28647 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
28648 * header in the HTTP response must be set to "text/xml".</em>
28652 var RecordDef = Roo.data.Record.create([
28653 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
28654 {name: 'occupation'} // This field will use "occupation" as the mapping.
28656 var myReader = new Roo.data.XmlReader({
28657 totalRecords: "results", // The element which contains the total dataset size (optional)
28658 record: "row", // The repeated element which contains row information
28659 id: "id" // The element within the row that provides an ID for the record (optional)
28663 * This would consume an XML file like this:
28667 <results>2</results>
28670 <name>Bill</name>
28671 <occupation>Gardener</occupation>
28675 <name>Ben</name>
28676 <occupation>Horticulturalist</occupation>
28680 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
28681 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
28682 * paged from the remote server.
28683 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
28684 * @cfg {String} success The DomQuery path to the success attribute used by forms.
28685 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
28686 * a record identifier value.
28688 * Create a new XmlReader
28689 * @param {Object} meta Metadata configuration options
28690 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
28691 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
28692 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
28694 Roo.data.XmlReader = function(meta, recordType){
28696 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
28698 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
28700 * This method is only used by a DataProxy which has retrieved data from a remote server.
28701 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
28702 * to contain a method called 'responseXML' that returns an XML document object.
28703 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
28704 * a cache of Roo.data.Records.
28706 read : function(response){
28707 var doc = response.responseXML;
28709 throw {message: "XmlReader.read: XML Document not available"};
28711 return this.readRecords(doc);
28715 * Create a data block containing Roo.data.Records from an XML document.
28716 * @param {Object} doc A parsed XML document.
28717 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
28718 * a cache of Roo.data.Records.
28720 readRecords : function(doc){
28722 * After any data loads/reads, the raw XML Document is available for further custom processing.
28723 * @type XMLDocument
28725 this.xmlData = doc;
28726 var root = doc.documentElement || doc;
28727 var q = Roo.DomQuery;
28728 var recordType = this.recordType, fields = recordType.prototype.fields;
28729 var sid = this.meta.id;
28730 var totalRecords = 0, success = true;
28731 if(this.meta.totalRecords){
28732 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
28735 if(this.meta.success){
28736 var sv = q.selectValue(this.meta.success, root, true);
28737 success = sv !== false && sv !== 'false';
28740 var ns = q.select(this.meta.record, root);
28741 for(var i = 0, len = ns.length; i < len; i++) {
28744 var id = sid ? q.selectValue(sid, n) : undefined;
28745 for(var j = 0, jlen = fields.length; j < jlen; j++){
28746 var f = fields.items[j];
28747 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
28749 values[f.name] = v;
28751 var record = new recordType(values, id);
28753 records[records.length] = record;
28759 totalRecords : totalRecords || records.length
28764 * Ext JS Library 1.1.1
28765 * Copyright(c) 2006-2007, Ext JS, LLC.
28767 * Originally Released Under LGPL - original licence link has changed is not relivant.
28770 * <script type="text/javascript">
28774 * @class Roo.data.ArrayReader
28775 * @extends Roo.data.DataReader
28776 * Data reader class to create an Array of Roo.data.Record objects from an Array.
28777 * Each element of that Array represents a row of data fields. The
28778 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
28779 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
28783 var RecordDef = Roo.data.Record.create([
28784 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
28785 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
28787 var myReader = new Roo.data.ArrayReader({
28788 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
28792 * This would consume an Array like this:
28794 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
28796 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
28798 * Create a new JsonReader
28799 * @param {Object} meta Metadata configuration options.
28800 * @param {Object} recordType Either an Array of field definition objects
28801 * as specified to {@link Roo.data.Record#create},
28802 * or an {@link Roo.data.Record} object
28803 * created using {@link Roo.data.Record#create}.
28805 Roo.data.ArrayReader = function(meta, recordType){
28806 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
28809 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
28811 * Create a data block containing Roo.data.Records from an XML document.
28812 * @param {Object} o An Array of row objects which represents the dataset.
28813 * @return {Object} data A data block which is used by an Roo.data.Store object as
28814 * a cache of Roo.data.Records.
28816 readRecords : function(o){
28817 var sid = this.meta ? this.meta.id : null;
28818 var recordType = this.recordType, fields = recordType.prototype.fields;
28821 for(var i = 0; i < root.length; i++){
28824 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
28825 for(var j = 0, jlen = fields.length; j < jlen; j++){
28826 var f = fields.items[j];
28827 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
28828 var v = n[k] !== undefined ? n[k] : f.defaultValue;
28830 values[f.name] = v;
28832 var record = new recordType(values, id);
28834 records[records.length] = record;
28838 totalRecords : records.length
28843 * Ext JS Library 1.1.1
28844 * Copyright(c) 2006-2007, Ext JS, LLC.
28846 * Originally Released Under LGPL - original licence link has changed is not relivant.
28849 * <script type="text/javascript">
28854 * @class Roo.data.Tree
28855 * @extends Roo.util.Observable
28856 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
28857 * in the tree have most standard DOM functionality.
28859 * @param {Node} root (optional) The root node
28861 Roo.data.Tree = function(root){
28862 this.nodeHash = {};
28864 * The root node for this tree
28869 this.setRootNode(root);
28874 * Fires when a new child node is appended to a node in this tree.
28875 * @param {Tree} tree The owner tree
28876 * @param {Node} parent The parent node
28877 * @param {Node} node The newly appended node
28878 * @param {Number} index The index of the newly appended node
28883 * Fires when a child node is removed from a node in this tree.
28884 * @param {Tree} tree The owner tree
28885 * @param {Node} parent The parent node
28886 * @param {Node} node The child node removed
28891 * Fires when a node is moved to a new location in the tree
28892 * @param {Tree} tree The owner tree
28893 * @param {Node} node The node moved
28894 * @param {Node} oldParent The old parent of this node
28895 * @param {Node} newParent The new parent of this node
28896 * @param {Number} index The index it was moved to
28901 * Fires when a new child node is inserted in a node in this tree.
28902 * @param {Tree} tree The owner tree
28903 * @param {Node} parent The parent node
28904 * @param {Node} node The child node inserted
28905 * @param {Node} refNode The child node the node was inserted before
28909 * @event beforeappend
28910 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
28911 * @param {Tree} tree The owner tree
28912 * @param {Node} parent The parent node
28913 * @param {Node} node The child node to be appended
28915 "beforeappend" : true,
28917 * @event beforeremove
28918 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
28919 * @param {Tree} tree The owner tree
28920 * @param {Node} parent The parent node
28921 * @param {Node} node The child node to be removed
28923 "beforeremove" : true,
28925 * @event beforemove
28926 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
28927 * @param {Tree} tree The owner tree
28928 * @param {Node} node The node being moved
28929 * @param {Node} oldParent The parent of the node
28930 * @param {Node} newParent The new parent the node is moving to
28931 * @param {Number} index The index it is being moved to
28933 "beforemove" : true,
28935 * @event beforeinsert
28936 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
28937 * @param {Tree} tree The owner tree
28938 * @param {Node} parent The parent node
28939 * @param {Node} node The child node to be inserted
28940 * @param {Node} refNode The child node the node is being inserted before
28942 "beforeinsert" : true
28945 Roo.data.Tree.superclass.constructor.call(this);
28948 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
28949 pathSeparator: "/",
28951 proxyNodeEvent : function(){
28952 return this.fireEvent.apply(this, arguments);
28956 * Returns the root node for this tree.
28959 getRootNode : function(){
28964 * Sets the root node for this tree.
28965 * @param {Node} node
28968 setRootNode : function(node){
28970 node.ownerTree = this;
28971 node.isRoot = true;
28972 this.registerNode(node);
28977 * Gets a node in this tree by its id.
28978 * @param {String} id
28981 getNodeById : function(id){
28982 return this.nodeHash[id];
28985 registerNode : function(node){
28986 this.nodeHash[node.id] = node;
28989 unregisterNode : function(node){
28990 delete this.nodeHash[node.id];
28993 toString : function(){
28994 return "[Tree"+(this.id?" "+this.id:"")+"]";
28999 * @class Roo.data.Node
29000 * @extends Roo.util.Observable
29001 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
29002 * @cfg {String} id The id for this node. If one is not specified, one is generated.
29004 * @param {Object} attributes The attributes/config for the node
29006 Roo.data.Node = function(attributes){
29008 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
29011 this.attributes = attributes || {};
29012 this.leaf = this.attributes.leaf;
29014 * The node id. @type String
29016 this.id = this.attributes.id;
29018 this.id = Roo.id(null, "ynode-");
29019 this.attributes.id = this.id;
29024 * All child nodes of this node. @type Array
29026 this.childNodes = [];
29027 if(!this.childNodes.indexOf){ // indexOf is a must
29028 this.childNodes.indexOf = function(o){
29029 for(var i = 0, len = this.length; i < len; i++){
29038 * The parent node for this node. @type Node
29040 this.parentNode = null;
29042 * The first direct child node of this node, or null if this node has no child nodes. @type Node
29044 this.firstChild = null;
29046 * The last direct child node of this node, or null if this node has no child nodes. @type Node
29048 this.lastChild = null;
29050 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
29052 this.previousSibling = null;
29054 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
29056 this.nextSibling = null;
29061 * Fires when a new child node is appended
29062 * @param {Tree} tree The owner tree
29063 * @param {Node} this This node
29064 * @param {Node} node The newly appended node
29065 * @param {Number} index The index of the newly appended node
29070 * Fires when a child node is removed
29071 * @param {Tree} tree The owner tree
29072 * @param {Node} this This node
29073 * @param {Node} node The removed node
29078 * Fires when this node is moved to a new location in the tree
29079 * @param {Tree} tree The owner tree
29080 * @param {Node} this This node
29081 * @param {Node} oldParent The old parent of this node
29082 * @param {Node} newParent The new parent of this node
29083 * @param {Number} index The index it was moved to
29088 * Fires when a new child node is inserted.
29089 * @param {Tree} tree The owner tree
29090 * @param {Node} this This node
29091 * @param {Node} node The child node inserted
29092 * @param {Node} refNode The child node the node was inserted before
29096 * @event beforeappend
29097 * Fires before a new child is appended, return false to cancel the append.
29098 * @param {Tree} tree The owner tree
29099 * @param {Node} this This node
29100 * @param {Node} node The child node to be appended
29102 "beforeappend" : true,
29104 * @event beforeremove
29105 * Fires before a child is removed, return false to cancel the remove.
29106 * @param {Tree} tree The owner tree
29107 * @param {Node} this This node
29108 * @param {Node} node The child node to be removed
29110 "beforeremove" : true,
29112 * @event beforemove
29113 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
29114 * @param {Tree} tree The owner tree
29115 * @param {Node} this This node
29116 * @param {Node} oldParent The parent of this node
29117 * @param {Node} newParent The new parent this node is moving to
29118 * @param {Number} index The index it is being moved to
29120 "beforemove" : true,
29122 * @event beforeinsert
29123 * Fires before a new child is inserted, return false to cancel the insert.
29124 * @param {Tree} tree The owner tree
29125 * @param {Node} this This node
29126 * @param {Node} node The child node to be inserted
29127 * @param {Node} refNode The child node the node is being inserted before
29129 "beforeinsert" : true
29131 this.listeners = this.attributes.listeners;
29132 Roo.data.Node.superclass.constructor.call(this);
29135 Roo.extend(Roo.data.Node, Roo.util.Observable, {
29136 fireEvent : function(evtName){
29137 // first do standard event for this node
29138 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
29141 // then bubble it up to the tree if the event wasn't cancelled
29142 var ot = this.getOwnerTree();
29144 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
29152 * Returns true if this node is a leaf
29153 * @return {Boolean}
29155 isLeaf : function(){
29156 return this.leaf === true;
29160 setFirstChild : function(node){
29161 this.firstChild = node;
29165 setLastChild : function(node){
29166 this.lastChild = node;
29171 * Returns true if this node is the last child of its parent
29172 * @return {Boolean}
29174 isLast : function(){
29175 return (!this.parentNode ? true : this.parentNode.lastChild == this);
29179 * Returns true if this node is the first child of its parent
29180 * @return {Boolean}
29182 isFirst : function(){
29183 return (!this.parentNode ? true : this.parentNode.firstChild == this);
29186 hasChildNodes : function(){
29187 return !this.isLeaf() && this.childNodes.length > 0;
29191 * Insert node(s) as the last child node of this node.
29192 * @param {Node/Array} node The node or Array of nodes to append
29193 * @return {Node} The appended node if single append, or null if an array was passed
29195 appendChild : function(node){
29197 if(node instanceof Array){
29199 }else if(arguments.length > 1){
29202 // if passed an array or multiple args do them one by one
29204 for(var i = 0, len = multi.length; i < len; i++) {
29205 this.appendChild(multi[i]);
29208 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
29211 var index = this.childNodes.length;
29212 var oldParent = node.parentNode;
29213 // it's a move, make sure we move it cleanly
29215 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
29218 oldParent.removeChild(node);
29220 index = this.childNodes.length;
29222 this.setFirstChild(node);
29224 this.childNodes.push(node);
29225 node.parentNode = this;
29226 var ps = this.childNodes[index-1];
29228 node.previousSibling = ps;
29229 ps.nextSibling = node;
29231 node.previousSibling = null;
29233 node.nextSibling = null;
29234 this.setLastChild(node);
29235 node.setOwnerTree(this.getOwnerTree());
29236 this.fireEvent("append", this.ownerTree, this, node, index);
29238 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
29245 * Removes a child node from this node.
29246 * @param {Node} node The node to remove
29247 * @return {Node} The removed node
29249 removeChild : function(node){
29250 var index = this.childNodes.indexOf(node);
29254 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
29258 // remove it from childNodes collection
29259 this.childNodes.splice(index, 1);
29262 if(node.previousSibling){
29263 node.previousSibling.nextSibling = node.nextSibling;
29265 if(node.nextSibling){
29266 node.nextSibling.previousSibling = node.previousSibling;
29269 // update child refs
29270 if(this.firstChild == node){
29271 this.setFirstChild(node.nextSibling);
29273 if(this.lastChild == node){
29274 this.setLastChild(node.previousSibling);
29277 node.setOwnerTree(null);
29278 // clear any references from the node
29279 node.parentNode = null;
29280 node.previousSibling = null;
29281 node.nextSibling = null;
29282 this.fireEvent("remove", this.ownerTree, this, node);
29287 * Inserts the first node before the second node in this nodes childNodes collection.
29288 * @param {Node} node The node to insert
29289 * @param {Node} refNode The node to insert before (if null the node is appended)
29290 * @return {Node} The inserted node
29292 insertBefore : function(node, refNode){
29293 if(!refNode){ // like standard Dom, refNode can be null for append
29294 return this.appendChild(node);
29297 if(node == refNode){
29301 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
29304 var index = this.childNodes.indexOf(refNode);
29305 var oldParent = node.parentNode;
29306 var refIndex = index;
29308 // when moving internally, indexes will change after remove
29309 if(oldParent == this && this.childNodes.indexOf(node) < index){
29313 // it's a move, make sure we move it cleanly
29315 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
29318 oldParent.removeChild(node);
29321 this.setFirstChild(node);
29323 this.childNodes.splice(refIndex, 0, node);
29324 node.parentNode = this;
29325 var ps = this.childNodes[refIndex-1];
29327 node.previousSibling = ps;
29328 ps.nextSibling = node;
29330 node.previousSibling = null;
29332 node.nextSibling = refNode;
29333 refNode.previousSibling = node;
29334 node.setOwnerTree(this.getOwnerTree());
29335 this.fireEvent("insert", this.ownerTree, this, node, refNode);
29337 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
29343 * Returns the child node at the specified index.
29344 * @param {Number} index
29347 item : function(index){
29348 return this.childNodes[index];
29352 * Replaces one child node in this node with another.
29353 * @param {Node} newChild The replacement node
29354 * @param {Node} oldChild The node to replace
29355 * @return {Node} The replaced node
29357 replaceChild : function(newChild, oldChild){
29358 this.insertBefore(newChild, oldChild);
29359 this.removeChild(oldChild);
29364 * Returns the index of a child node
29365 * @param {Node} node
29366 * @return {Number} The index of the node or -1 if it was not found
29368 indexOf : function(child){
29369 return this.childNodes.indexOf(child);
29373 * Returns the tree this node is in.
29376 getOwnerTree : function(){
29377 // if it doesn't have one, look for one
29378 if(!this.ownerTree){
29382 this.ownerTree = p.ownerTree;
29388 return this.ownerTree;
29392 * Returns depth of this node (the root node has a depth of 0)
29395 getDepth : function(){
29398 while(p.parentNode){
29406 setOwnerTree : function(tree){
29407 // if it's move, we need to update everyone
29408 if(tree != this.ownerTree){
29409 if(this.ownerTree){
29410 this.ownerTree.unregisterNode(this);
29412 this.ownerTree = tree;
29413 var cs = this.childNodes;
29414 for(var i = 0, len = cs.length; i < len; i++) {
29415 cs[i].setOwnerTree(tree);
29418 tree.registerNode(this);
29424 * Returns the path for this node. The path can be used to expand or select this node programmatically.
29425 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
29426 * @return {String} The path
29428 getPath : function(attr){
29429 attr = attr || "id";
29430 var p = this.parentNode;
29431 var b = [this.attributes[attr]];
29433 b.unshift(p.attributes[attr]);
29436 var sep = this.getOwnerTree().pathSeparator;
29437 return sep + b.join(sep);
29441 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
29442 * function call will be the scope provided or the current node. The arguments to the function
29443 * will be the args provided or the current node. If the function returns false at any point,
29444 * the bubble is stopped.
29445 * @param {Function} fn The function to call
29446 * @param {Object} scope (optional) The scope of the function (defaults to current node)
29447 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
29449 bubble : function(fn, scope, args){
29452 if(fn.call(scope || p, args || p) === false){
29460 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
29461 * function call will be the scope provided or the current node. The arguments to the function
29462 * will be the args provided or the current node. If the function returns false at any point,
29463 * the cascade is stopped on that branch.
29464 * @param {Function} fn The function to call
29465 * @param {Object} scope (optional) The scope of the function (defaults to current node)
29466 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
29468 cascade : function(fn, scope, args){
29469 if(fn.call(scope || this, args || this) !== false){
29470 var cs = this.childNodes;
29471 for(var i = 0, len = cs.length; i < len; i++) {
29472 cs[i].cascade(fn, scope, args);
29478 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
29479 * function call will be the scope provided or the current node. The arguments to the function
29480 * will be the args provided or the current node. If the function returns false at any point,
29481 * the iteration stops.
29482 * @param {Function} fn The function to call
29483 * @param {Object} scope (optional) The scope of the function (defaults to current node)
29484 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
29486 eachChild : function(fn, scope, args){
29487 var cs = this.childNodes;
29488 for(var i = 0, len = cs.length; i < len; i++) {
29489 if(fn.call(scope || this, args || cs[i]) === false){
29496 * Finds the first child that has the attribute with the specified value.
29497 * @param {String} attribute The attribute name
29498 * @param {Mixed} value The value to search for
29499 * @return {Node} The found child or null if none was found
29501 findChild : function(attribute, value){
29502 var cs = this.childNodes;
29503 for(var i = 0, len = cs.length; i < len; i++) {
29504 if(cs[i].attributes[attribute] == value){
29512 * Finds the first child by a custom function. The child matches if the function passed
29514 * @param {Function} fn
29515 * @param {Object} scope (optional)
29516 * @return {Node} The found child or null if none was found
29518 findChildBy : function(fn, scope){
29519 var cs = this.childNodes;
29520 for(var i = 0, len = cs.length; i < len; i++) {
29521 if(fn.call(scope||cs[i], cs[i]) === true){
29529 * Sorts this nodes children using the supplied sort function
29530 * @param {Function} fn
29531 * @param {Object} scope (optional)
29533 sort : function(fn, scope){
29534 var cs = this.childNodes;
29535 var len = cs.length;
29537 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
29539 for(var i = 0; i < len; i++){
29541 n.previousSibling = cs[i-1];
29542 n.nextSibling = cs[i+1];
29544 this.setFirstChild(n);
29547 this.setLastChild(n);
29554 * Returns true if this node is an ancestor (at any point) of the passed node.
29555 * @param {Node} node
29556 * @return {Boolean}
29558 contains : function(node){
29559 return node.isAncestor(this);
29563 * Returns true if the passed node is an ancestor (at any point) of this node.
29564 * @param {Node} node
29565 * @return {Boolean}
29567 isAncestor : function(node){
29568 var p = this.parentNode;
29578 toString : function(){
29579 return "[Node"+(this.id?" "+this.id:"")+"]";
29583 * Ext JS Library 1.1.1
29584 * Copyright(c) 2006-2007, Ext JS, LLC.
29586 * Originally Released Under LGPL - original licence link has changed is not relivant.
29589 * <script type="text/javascript">
29594 * @extends Roo.Element
29595 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
29596 * automatic maintaining of shadow/shim positions.
29597 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
29598 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
29599 * you can pass a string with a CSS class name. False turns off the shadow.
29600 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
29601 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
29602 * @cfg {String} cls CSS class to add to the element
29603 * @cfg {Number} zindex Starting z-index (defaults to 11000)
29604 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
29606 * @param {Object} config An object with config options.
29607 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
29610 Roo.Layer = function(config, existingEl){
29611 config = config || {};
29612 var dh = Roo.DomHelper;
29613 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
29615 this.dom = Roo.getDom(existingEl);
29618 var o = config.dh || {tag: "div", cls: "x-layer"};
29619 this.dom = dh.append(pel, o);
29622 this.addClass(config.cls);
29624 this.constrain = config.constrain !== false;
29625 this.visibilityMode = Roo.Element.VISIBILITY;
29627 this.id = this.dom.id = config.id;
29629 this.id = Roo.id(this.dom);
29631 this.zindex = config.zindex || this.getZIndex();
29632 this.position("absolute", this.zindex);
29634 this.shadowOffset = config.shadowOffset || 4;
29635 this.shadow = new Roo.Shadow({
29636 offset : this.shadowOffset,
29637 mode : config.shadow
29640 this.shadowOffset = 0;
29642 this.useShim = config.shim !== false && Roo.useShims;
29643 this.useDisplay = config.useDisplay;
29647 var supr = Roo.Element.prototype;
29649 // shims are shared among layer to keep from having 100 iframes
29652 Roo.extend(Roo.Layer, Roo.Element, {
29654 getZIndex : function(){
29655 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
29658 getShim : function(){
29665 var shim = shims.shift();
29667 shim = this.createShim();
29668 shim.enableDisplayMode('block');
29669 shim.dom.style.display = 'none';
29670 shim.dom.style.visibility = 'visible';
29672 var pn = this.dom.parentNode;
29673 if(shim.dom.parentNode != pn){
29674 pn.insertBefore(shim.dom, this.dom);
29676 shim.setStyle('z-index', this.getZIndex()-2);
29681 hideShim : function(){
29683 this.shim.setDisplayed(false);
29684 shims.push(this.shim);
29689 disableShadow : function(){
29691 this.shadowDisabled = true;
29692 this.shadow.hide();
29693 this.lastShadowOffset = this.shadowOffset;
29694 this.shadowOffset = 0;
29698 enableShadow : function(show){
29700 this.shadowDisabled = false;
29701 this.shadowOffset = this.lastShadowOffset;
29702 delete this.lastShadowOffset;
29710 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
29711 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
29712 sync : function(doShow){
29713 var sw = this.shadow;
29714 if(!this.updating && this.isVisible() && (sw || this.useShim)){
29715 var sh = this.getShim();
29717 var w = this.getWidth(),
29718 h = this.getHeight();
29720 var l = this.getLeft(true),
29721 t = this.getTop(true);
29723 if(sw && !this.shadowDisabled){
29724 if(doShow && !sw.isVisible()){
29727 sw.realign(l, t, w, h);
29733 // fit the shim behind the shadow, so it is shimmed too
29734 var a = sw.adjusts, s = sh.dom.style;
29735 s.left = (Math.min(l, l+a.l))+"px";
29736 s.top = (Math.min(t, t+a.t))+"px";
29737 s.width = (w+a.w)+"px";
29738 s.height = (h+a.h)+"px";
29745 sh.setLeftTop(l, t);
29752 destroy : function(){
29755 this.shadow.hide();
29757 this.removeAllListeners();
29758 var pn = this.dom.parentNode;
29760 pn.removeChild(this.dom);
29762 Roo.Element.uncache(this.id);
29765 remove : function(){
29770 beginUpdate : function(){
29771 this.updating = true;
29775 endUpdate : function(){
29776 this.updating = false;
29781 hideUnders : function(negOffset){
29783 this.shadow.hide();
29789 constrainXY : function(){
29790 if(this.constrain){
29791 var vw = Roo.lib.Dom.getViewWidth(),
29792 vh = Roo.lib.Dom.getViewHeight();
29793 var s = Roo.get(document).getScroll();
29795 var xy = this.getXY();
29796 var x = xy[0], y = xy[1];
29797 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
29798 // only move it if it needs it
29800 // first validate right/bottom
29801 if((x + w) > vw+s.left){
29802 x = vw - w - this.shadowOffset;
29805 if((y + h) > vh+s.top){
29806 y = vh - h - this.shadowOffset;
29809 // then make sure top/left isn't negative
29820 var ay = this.avoidY;
29821 if(y <= ay && (y+h) >= ay){
29827 supr.setXY.call(this, xy);
29833 isVisible : function(){
29834 return this.visible;
29838 showAction : function(){
29839 this.visible = true; // track visibility to prevent getStyle calls
29840 if(this.useDisplay === true){
29841 this.setDisplayed("");
29842 }else if(this.lastXY){
29843 supr.setXY.call(this, this.lastXY);
29844 }else if(this.lastLT){
29845 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
29850 hideAction : function(){
29851 this.visible = false;
29852 if(this.useDisplay === true){
29853 this.setDisplayed(false);
29855 this.setLeftTop(-10000,-10000);
29859 // overridden Element method
29860 setVisible : function(v, a, d, c, e){
29865 var cb = function(){
29870 }.createDelegate(this);
29871 supr.setVisible.call(this, true, true, d, cb, e);
29874 this.hideUnders(true);
29883 }.createDelegate(this);
29885 supr.setVisible.call(this, v, a, d, cb, e);
29894 storeXY : function(xy){
29895 delete this.lastLT;
29899 storeLeftTop : function(left, top){
29900 delete this.lastXY;
29901 this.lastLT = [left, top];
29905 beforeFx : function(){
29906 this.beforeAction();
29907 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
29911 afterFx : function(){
29912 Roo.Layer.superclass.afterFx.apply(this, arguments);
29913 this.sync(this.isVisible());
29917 beforeAction : function(){
29918 if(!this.updating && this.shadow){
29919 this.shadow.hide();
29923 // overridden Element method
29924 setLeft : function(left){
29925 this.storeLeftTop(left, this.getTop(true));
29926 supr.setLeft.apply(this, arguments);
29930 setTop : function(top){
29931 this.storeLeftTop(this.getLeft(true), top);
29932 supr.setTop.apply(this, arguments);
29936 setLeftTop : function(left, top){
29937 this.storeLeftTop(left, top);
29938 supr.setLeftTop.apply(this, arguments);
29942 setXY : function(xy, a, d, c, e){
29944 this.beforeAction();
29946 var cb = this.createCB(c);
29947 supr.setXY.call(this, xy, a, d, cb, e);
29954 createCB : function(c){
29965 // overridden Element method
29966 setX : function(x, a, d, c, e){
29967 this.setXY([x, this.getY()], a, d, c, e);
29970 // overridden Element method
29971 setY : function(y, a, d, c, e){
29972 this.setXY([this.getX(), y], a, d, c, e);
29975 // overridden Element method
29976 setSize : function(w, h, a, d, c, e){
29977 this.beforeAction();
29978 var cb = this.createCB(c);
29979 supr.setSize.call(this, w, h, a, d, cb, e);
29985 // overridden Element method
29986 setWidth : function(w, a, d, c, e){
29987 this.beforeAction();
29988 var cb = this.createCB(c);
29989 supr.setWidth.call(this, w, a, d, cb, e);
29995 // overridden Element method
29996 setHeight : function(h, a, d, c, e){
29997 this.beforeAction();
29998 var cb = this.createCB(c);
29999 supr.setHeight.call(this, h, a, d, cb, e);
30005 // overridden Element method
30006 setBounds : function(x, y, w, h, a, d, c, e){
30007 this.beforeAction();
30008 var cb = this.createCB(c);
30010 this.storeXY([x, y]);
30011 supr.setXY.call(this, [x, y]);
30012 supr.setSize.call(this, w, h, a, d, cb, e);
30015 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
30021 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
30022 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
30023 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
30024 * @param {Number} zindex The new z-index to set
30025 * @return {this} The Layer
30027 setZIndex : function(zindex){
30028 this.zindex = zindex;
30029 this.setStyle("z-index", zindex + 2);
30031 this.shadow.setZIndex(zindex + 1);
30034 this.shim.setStyle("z-index", zindex);
30040 * Ext JS Library 1.1.1
30041 * Copyright(c) 2006-2007, Ext JS, LLC.
30043 * Originally Released Under LGPL - original licence link has changed is not relivant.
30046 * <script type="text/javascript">
30051 * @class Roo.Shadow
30052 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
30053 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
30054 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
30056 * Create a new Shadow
30057 * @param {Object} config The config object
30059 Roo.Shadow = function(config){
30060 Roo.apply(this, config);
30061 if(typeof this.mode != "string"){
30062 this.mode = this.defaultMode;
30064 var o = this.offset, a = {h: 0};
30065 var rad = Math.floor(this.offset/2);
30066 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
30072 a.l -= this.offset + rad;
30073 a.t -= this.offset + rad;
30084 a.l -= (this.offset - rad);
30085 a.t -= this.offset + rad;
30087 a.w -= (this.offset - rad)*2;
30098 a.l -= (this.offset - rad);
30099 a.t -= (this.offset - rad);
30101 a.w -= (this.offset + rad + 1);
30102 a.h -= (this.offset + rad);
30111 Roo.Shadow.prototype = {
30113 * @cfg {String} mode
30114 * The shadow display mode. Supports the following options:<br />
30115 * sides: Shadow displays on both sides and bottom only<br />
30116 * frame: Shadow displays equally on all four sides<br />
30117 * drop: Traditional bottom-right drop shadow (default)
30120 * @cfg {String} offset
30121 * The number of pixels to offset the shadow from the element (defaults to 4)
30126 defaultMode: "drop",
30129 * Displays the shadow under the target element
30130 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
30132 show : function(target){
30133 target = Roo.get(target);
30135 this.el = Roo.Shadow.Pool.pull();
30136 if(this.el.dom.nextSibling != target.dom){
30137 this.el.insertBefore(target);
30140 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
30142 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
30145 target.getLeft(true),
30146 target.getTop(true),
30150 this.el.dom.style.display = "block";
30154 * Returns true if the shadow is visible, else false
30156 isVisible : function(){
30157 return this.el ? true : false;
30161 * Direct alignment when values are already available. Show must be called at least once before
30162 * calling this method to ensure it is initialized.
30163 * @param {Number} left The target element left position
30164 * @param {Number} top The target element top position
30165 * @param {Number} width The target element width
30166 * @param {Number} height The target element height
30168 realign : function(l, t, w, h){
30172 var a = this.adjusts, d = this.el.dom, s = d.style;
30174 s.left = (l+a.l)+"px";
30175 s.top = (t+a.t)+"px";
30176 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
30178 if(s.width != sws || s.height != shs){
30182 var cn = d.childNodes;
30183 var sww = Math.max(0, (sw-12))+"px";
30184 cn[0].childNodes[1].style.width = sww;
30185 cn[1].childNodes[1].style.width = sww;
30186 cn[2].childNodes[1].style.width = sww;
30187 cn[1].style.height = Math.max(0, (sh-12))+"px";
30193 * Hides this shadow
30197 this.el.dom.style.display = "none";
30198 Roo.Shadow.Pool.push(this.el);
30204 * Adjust the z-index of this shadow
30205 * @param {Number} zindex The new z-index
30207 setZIndex : function(z){
30210 this.el.setStyle("z-index", z);
30215 // Private utility class that manages the internal Shadow cache
30216 Roo.Shadow.Pool = function(){
30218 var markup = Roo.isIE ?
30219 '<div class="x-ie-shadow"></div>' :
30220 '<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>';
30223 var sh = p.shift();
30225 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
30226 sh.autoBoxAdjust = false;
30231 push : function(sh){
30237 * Ext JS Library 1.1.1
30238 * Copyright(c) 2006-2007, Ext JS, LLC.
30240 * Originally Released Under LGPL - original licence link has changed is not relivant.
30243 * <script type="text/javascript">
30248 * @class Roo.SplitBar
30249 * @extends Roo.util.Observable
30250 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
30254 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
30255 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
30256 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
30257 split.minSize = 100;
30258 split.maxSize = 600;
30259 split.animate = true;
30260 split.on('moved', splitterMoved);
30263 * Create a new SplitBar
30264 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
30265 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
30266 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30267 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
30268 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
30269 position of the SplitBar).
30271 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
30274 this.el = Roo.get(dragElement, true);
30275 this.el.dom.unselectable = "on";
30277 this.resizingEl = Roo.get(resizingElement, true);
30281 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30282 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
30285 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
30288 * The minimum size of the resizing element. (Defaults to 0)
30294 * The maximum size of the resizing element. (Defaults to 2000)
30297 this.maxSize = 2000;
30300 * Whether to animate the transition to the new size
30303 this.animate = false;
30306 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
30309 this.useShim = false;
30314 if(!existingProxy){
30316 this.proxy = Roo.SplitBar.createProxy(this.orientation);
30318 this.proxy = Roo.get(existingProxy).dom;
30321 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
30324 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
30327 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
30330 this.dragSpecs = {};
30333 * @private The adapter to use to positon and resize elements
30335 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
30336 this.adapter.init(this);
30338 if(this.orientation == Roo.SplitBar.HORIZONTAL){
30340 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
30341 this.el.addClass("x-splitbar-h");
30344 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
30345 this.el.addClass("x-splitbar-v");
30351 * Fires when the splitter is moved (alias for {@link #event-moved})
30352 * @param {Roo.SplitBar} this
30353 * @param {Number} newSize the new width or height
30358 * Fires when the splitter is moved
30359 * @param {Roo.SplitBar} this
30360 * @param {Number} newSize the new width or height
30364 * @event beforeresize
30365 * Fires before the splitter is dragged
30366 * @param {Roo.SplitBar} this
30368 "beforeresize" : true,
30370 "beforeapply" : true
30373 Roo.util.Observable.call(this);
30376 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
30377 onStartProxyDrag : function(x, y){
30378 this.fireEvent("beforeresize", this);
30380 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
30382 o.enableDisplayMode("block");
30383 // all splitbars share the same overlay
30384 Roo.SplitBar.prototype.overlay = o;
30386 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30387 this.overlay.show();
30388 Roo.get(this.proxy).setDisplayed("block");
30389 var size = this.adapter.getElementSize(this);
30390 this.activeMinSize = this.getMinimumSize();;
30391 this.activeMaxSize = this.getMaximumSize();;
30392 var c1 = size - this.activeMinSize;
30393 var c2 = Math.max(this.activeMaxSize - size, 0);
30394 if(this.orientation == Roo.SplitBar.HORIZONTAL){
30395 this.dd.resetConstraints();
30396 this.dd.setXConstraint(
30397 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
30398 this.placement == Roo.SplitBar.LEFT ? c2 : c1
30400 this.dd.setYConstraint(0, 0);
30402 this.dd.resetConstraints();
30403 this.dd.setXConstraint(0, 0);
30404 this.dd.setYConstraint(
30405 this.placement == Roo.SplitBar.TOP ? c1 : c2,
30406 this.placement == Roo.SplitBar.TOP ? c2 : c1
30409 this.dragSpecs.startSize = size;
30410 this.dragSpecs.startPoint = [x, y];
30411 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
30415 * @private Called after the drag operation by the DDProxy
30417 onEndProxyDrag : function(e){
30418 Roo.get(this.proxy).setDisplayed(false);
30419 var endPoint = Roo.lib.Event.getXY(e);
30421 this.overlay.hide();
30424 if(this.orientation == Roo.SplitBar.HORIZONTAL){
30425 newSize = this.dragSpecs.startSize +
30426 (this.placement == Roo.SplitBar.LEFT ?
30427 endPoint[0] - this.dragSpecs.startPoint[0] :
30428 this.dragSpecs.startPoint[0] - endPoint[0]
30431 newSize = this.dragSpecs.startSize +
30432 (this.placement == Roo.SplitBar.TOP ?
30433 endPoint[1] - this.dragSpecs.startPoint[1] :
30434 this.dragSpecs.startPoint[1] - endPoint[1]
30437 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
30438 if(newSize != this.dragSpecs.startSize){
30439 if(this.fireEvent('beforeapply', this, newSize) !== false){
30440 this.adapter.setElementSize(this, newSize);
30441 this.fireEvent("moved", this, newSize);
30442 this.fireEvent("resize", this, newSize);
30448 * Get the adapter this SplitBar uses
30449 * @return The adapter object
30451 getAdapter : function(){
30452 return this.adapter;
30456 * Set the adapter this SplitBar uses
30457 * @param {Object} adapter A SplitBar adapter object
30459 setAdapter : function(adapter){
30460 this.adapter = adapter;
30461 this.adapter.init(this);
30465 * Gets the minimum size for the resizing element
30466 * @return {Number} The minimum size
30468 getMinimumSize : function(){
30469 return this.minSize;
30473 * Sets the minimum size for the resizing element
30474 * @param {Number} minSize The minimum size
30476 setMinimumSize : function(minSize){
30477 this.minSize = minSize;
30481 * Gets the maximum size for the resizing element
30482 * @return {Number} The maximum size
30484 getMaximumSize : function(){
30485 return this.maxSize;
30489 * Sets the maximum size for the resizing element
30490 * @param {Number} maxSize The maximum size
30492 setMaximumSize : function(maxSize){
30493 this.maxSize = maxSize;
30497 * Sets the initialize size for the resizing element
30498 * @param {Number} size The initial size
30500 setCurrentSize : function(size){
30501 var oldAnimate = this.animate;
30502 this.animate = false;
30503 this.adapter.setElementSize(this, size);
30504 this.animate = oldAnimate;
30508 * Destroy this splitbar.
30509 * @param {Boolean} removeEl True to remove the element
30511 destroy : function(removeEl){
30513 this.shim.remove();
30516 this.proxy.parentNode.removeChild(this.proxy);
30524 * @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.
30526 Roo.SplitBar.createProxy = function(dir){
30527 var proxy = new Roo.Element(document.createElement("div"));
30528 proxy.unselectable();
30529 var cls = 'x-splitbar-proxy';
30530 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
30531 document.body.appendChild(proxy.dom);
30536 * @class Roo.SplitBar.BasicLayoutAdapter
30537 * Default Adapter. It assumes the splitter and resizing element are not positioned
30538 * elements and only gets/sets the width of the element. Generally used for table based layouts.
30540 Roo.SplitBar.BasicLayoutAdapter = function(){
30543 Roo.SplitBar.BasicLayoutAdapter.prototype = {
30544 // do nothing for now
30545 init : function(s){
30549 * Called before drag operations to get the current size of the resizing element.
30550 * @param {Roo.SplitBar} s The SplitBar using this adapter
30552 getElementSize : function(s){
30553 if(s.orientation == Roo.SplitBar.HORIZONTAL){
30554 return s.resizingEl.getWidth();
30556 return s.resizingEl.getHeight();
30561 * Called after drag operations to set the size of the resizing element.
30562 * @param {Roo.SplitBar} s The SplitBar using this adapter
30563 * @param {Number} newSize The new size to set
30564 * @param {Function} onComplete A function to be invoked when resizing is complete
30566 setElementSize : function(s, newSize, onComplete){
30567 if(s.orientation == Roo.SplitBar.HORIZONTAL){
30569 s.resizingEl.setWidth(newSize);
30571 onComplete(s, newSize);
30574 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
30579 s.resizingEl.setHeight(newSize);
30581 onComplete(s, newSize);
30584 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
30591 *@class Roo.SplitBar.AbsoluteLayoutAdapter
30592 * @extends Roo.SplitBar.BasicLayoutAdapter
30593 * Adapter that moves the splitter element to align with the resized sizing element.
30594 * Used with an absolute positioned SplitBar.
30595 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
30596 * document.body, make sure you assign an id to the body element.
30598 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
30599 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
30600 this.container = Roo.get(container);
30603 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
30604 init : function(s){
30605 this.basic.init(s);
30608 getElementSize : function(s){
30609 return this.basic.getElementSize(s);
30612 setElementSize : function(s, newSize, onComplete){
30613 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
30616 moveSplitter : function(s){
30617 var yes = Roo.SplitBar;
30618 switch(s.placement){
30620 s.el.setX(s.resizingEl.getRight());
30623 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
30626 s.el.setY(s.resizingEl.getBottom());
30629 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
30636 * Orientation constant - Create a vertical SplitBar
30640 Roo.SplitBar.VERTICAL = 1;
30643 * Orientation constant - Create a horizontal SplitBar
30647 Roo.SplitBar.HORIZONTAL = 2;
30650 * Placement constant - The resizing element is to the left of the splitter element
30654 Roo.SplitBar.LEFT = 1;
30657 * Placement constant - The resizing element is to the right of the splitter element
30661 Roo.SplitBar.RIGHT = 2;
30664 * Placement constant - The resizing element is positioned above the splitter element
30668 Roo.SplitBar.TOP = 3;
30671 * Placement constant - The resizing element is positioned under splitter element
30675 Roo.SplitBar.BOTTOM = 4;
30678 * Ext JS Library 1.1.1
30679 * Copyright(c) 2006-2007, Ext JS, LLC.
30681 * Originally Released Under LGPL - original licence link has changed is not relivant.
30684 * <script type="text/javascript">
30689 * @extends Roo.util.Observable
30690 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
30691 * This class also supports single and multi selection modes. <br>
30692 * Create a data model bound view:
30694 var store = new Roo.data.Store(...);
30696 var view = new Roo.View({
30698 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
30700 singleSelect: true,
30701 selectedClass: "ydataview-selected",
30705 // listen for node click?
30706 view.on("click", function(vw, index, node, e){
30707 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
30711 dataModel.load("foobar.xml");
30713 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
30715 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
30716 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
30718 * Note: old style constructor is still suported (container, template, config)
30721 * Create a new View
30722 * @param {Object} config The config object
30725 Roo.View = function(config, depreciated_tpl, depreciated_config){
30727 this.parent = false;
30729 if (typeof(depreciated_tpl) == 'undefined') {
30730 // new way.. - universal constructor.
30731 Roo.apply(this, config);
30732 this.el = Roo.get(this.el);
30735 this.el = Roo.get(config);
30736 this.tpl = depreciated_tpl;
30737 Roo.apply(this, depreciated_config);
30739 this.wrapEl = this.el.wrap().wrap();
30740 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
30743 if(typeof(this.tpl) == "string"){
30744 this.tpl = new Roo.Template(this.tpl);
30746 // support xtype ctors..
30747 this.tpl = new Roo.factory(this.tpl, Roo);
30751 this.tpl.compile();
30756 * @event beforeclick
30757 * Fires before a click is processed. Returns false to cancel the default action.
30758 * @param {Roo.View} this
30759 * @param {Number} index The index of the target node
30760 * @param {HTMLElement} node The target node
30761 * @param {Roo.EventObject} e The raw event object
30763 "beforeclick" : true,
30766 * Fires when a template node is clicked.
30767 * @param {Roo.View} this
30768 * @param {Number} index The index of the target node
30769 * @param {HTMLElement} node The target node
30770 * @param {Roo.EventObject} e The raw event object
30775 * Fires when a template node is double clicked.
30776 * @param {Roo.View} this
30777 * @param {Number} index The index of the target node
30778 * @param {HTMLElement} node The target node
30779 * @param {Roo.EventObject} e The raw event object
30783 * @event contextmenu
30784 * Fires when a template node is right clicked.
30785 * @param {Roo.View} this
30786 * @param {Number} index The index of the target node
30787 * @param {HTMLElement} node The target node
30788 * @param {Roo.EventObject} e The raw event object
30790 "contextmenu" : true,
30792 * @event selectionchange
30793 * Fires when the selected nodes change.
30794 * @param {Roo.View} this
30795 * @param {Array} selections Array of the selected nodes
30797 "selectionchange" : true,
30800 * @event beforeselect
30801 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
30802 * @param {Roo.View} this
30803 * @param {HTMLElement} node The node to be selected
30804 * @param {Array} selections Array of currently selected nodes
30806 "beforeselect" : true,
30808 * @event preparedata
30809 * Fires on every row to render, to allow you to change the data.
30810 * @param {Roo.View} this
30811 * @param {Object} data to be rendered (change this)
30813 "preparedata" : true
30821 "click": this.onClick,
30822 "dblclick": this.onDblClick,
30823 "contextmenu": this.onContextMenu,
30827 this.selections = [];
30829 this.cmp = new Roo.CompositeElementLite([]);
30831 this.store = Roo.factory(this.store, Roo.data);
30832 this.setStore(this.store, true);
30835 if ( this.footer && this.footer.xtype) {
30837 var fctr = this.wrapEl.appendChild(document.createElement("div"));
30839 this.footer.dataSource = this.store;
30840 this.footer.container = fctr;
30841 this.footer = Roo.factory(this.footer, Roo);
30842 fctr.insertFirst(this.el);
30844 // this is a bit insane - as the paging toolbar seems to detach the el..
30845 // dom.parentNode.parentNode.parentNode
30846 // they get detached?
30850 Roo.View.superclass.constructor.call(this);
30855 Roo.extend(Roo.View, Roo.util.Observable, {
30858 * @cfg {Roo.data.Store} store Data store to load data from.
30863 * @cfg {String|Roo.Element} el The container element.
30868 * @cfg {String|Roo.Template} tpl The template used by this View
30872 * @cfg {String} dataName the named area of the template to use as the data area
30873 * Works with domtemplates roo-name="name"
30877 * @cfg {String} selectedClass The css class to add to selected nodes
30879 selectedClass : "x-view-selected",
30881 * @cfg {String} emptyText The empty text to show when nothing is loaded.
30886 * @cfg {String} text to display on mask (default Loading)
30890 * @cfg {Boolean} multiSelect Allow multiple selection
30892 multiSelect : false,
30894 * @cfg {Boolean} singleSelect Allow single selection
30896 singleSelect: false,
30899 * @cfg {Boolean} toggleSelect - selecting
30901 toggleSelect : false,
30904 * @cfg {Boolean} tickable - selecting
30909 * Returns the element this view is bound to.
30910 * @return {Roo.Element}
30912 getEl : function(){
30913 return this.wrapEl;
30919 * Refreshes the view. - called by datachanged on the store. - do not call directly.
30921 refresh : function(){
30922 //Roo.log('refresh');
30925 // if we are using something like 'domtemplate', then
30926 // the what gets used is:
30927 // t.applySubtemplate(NAME, data, wrapping data..)
30928 // the outer template then get' applied with
30929 // the store 'extra data'
30930 // and the body get's added to the
30931 // roo-name="data" node?
30932 // <span class='roo-tpl-{name}'></span> ?????
30936 this.clearSelections();
30937 this.el.update("");
30939 var records = this.store.getRange();
30940 if(records.length < 1) {
30942 // is this valid?? = should it render a template??
30944 this.el.update(this.emptyText);
30948 if (this.dataName) {
30949 this.el.update(t.apply(this.store.meta)); //????
30950 el = this.el.child('.roo-tpl-' + this.dataName);
30953 for(var i = 0, len = records.length; i < len; i++){
30954 var data = this.prepareData(records[i].data, i, records[i]);
30955 this.fireEvent("preparedata", this, data, i, records[i]);
30957 var d = Roo.apply({}, data);
30960 Roo.apply(d, {'roo-id' : Roo.id()});
30964 Roo.each(this.parent.item, function(item){
30965 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
30968 Roo.apply(d, {'roo-data-checked' : 'checked'});
30972 html[html.length] = Roo.util.Format.trim(
30974 t.applySubtemplate(this.dataName, d, this.store.meta) :
30981 el.update(html.join(""));
30982 this.nodes = el.dom.childNodes;
30983 this.updateIndexes(0);
30988 * Function to override to reformat the data that is sent to
30989 * the template for each node.
30990 * DEPRICATED - use the preparedata event handler.
30991 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
30992 * a JSON object for an UpdateManager bound view).
30994 prepareData : function(data, index, record)
30996 this.fireEvent("preparedata", this, data, index, record);
31000 onUpdate : function(ds, record){
31001 // Roo.log('on update');
31002 this.clearSelections();
31003 var index = this.store.indexOf(record);
31004 var n = this.nodes[index];
31005 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
31006 n.parentNode.removeChild(n);
31007 this.updateIndexes(index, index);
31013 onAdd : function(ds, records, index)
31015 //Roo.log(['on Add', ds, records, index] );
31016 this.clearSelections();
31017 if(this.nodes.length == 0){
31021 var n = this.nodes[index];
31022 for(var i = 0, len = records.length; i < len; i++){
31023 var d = this.prepareData(records[i].data, i, records[i]);
31025 this.tpl.insertBefore(n, d);
31028 this.tpl.append(this.el, d);
31031 this.updateIndexes(index);
31034 onRemove : function(ds, record, index){
31035 // Roo.log('onRemove');
31036 this.clearSelections();
31037 var el = this.dataName ?
31038 this.el.child('.roo-tpl-' + this.dataName) :
31041 el.dom.removeChild(this.nodes[index]);
31042 this.updateIndexes(index);
31046 * Refresh an individual node.
31047 * @param {Number} index
31049 refreshNode : function(index){
31050 this.onUpdate(this.store, this.store.getAt(index));
31053 updateIndexes : function(startIndex, endIndex){
31054 var ns = this.nodes;
31055 startIndex = startIndex || 0;
31056 endIndex = endIndex || ns.length - 1;
31057 for(var i = startIndex; i <= endIndex; i++){
31058 ns[i].nodeIndex = i;
31063 * Changes the data store this view uses and refresh the view.
31064 * @param {Store} store
31066 setStore : function(store, initial){
31067 if(!initial && this.store){
31068 this.store.un("datachanged", this.refresh);
31069 this.store.un("add", this.onAdd);
31070 this.store.un("remove", this.onRemove);
31071 this.store.un("update", this.onUpdate);
31072 this.store.un("clear", this.refresh);
31073 this.store.un("beforeload", this.onBeforeLoad);
31074 this.store.un("load", this.onLoad);
31075 this.store.un("loadexception", this.onLoad);
31079 store.on("datachanged", this.refresh, this);
31080 store.on("add", this.onAdd, this);
31081 store.on("remove", this.onRemove, this);
31082 store.on("update", this.onUpdate, this);
31083 store.on("clear", this.refresh, this);
31084 store.on("beforeload", this.onBeforeLoad, this);
31085 store.on("load", this.onLoad, this);
31086 store.on("loadexception", this.onLoad, this);
31094 * onbeforeLoad - masks the loading area.
31097 onBeforeLoad : function(store,opts)
31099 //Roo.log('onBeforeLoad');
31101 this.el.update("");
31103 this.el.mask(this.mask ? this.mask : "Loading" );
31105 onLoad : function ()
31112 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
31113 * @param {HTMLElement} node
31114 * @return {HTMLElement} The template node
31116 findItemFromChild : function(node){
31117 var el = this.dataName ?
31118 this.el.child('.roo-tpl-' + this.dataName,true) :
31121 if(!node || node.parentNode == el){
31124 var p = node.parentNode;
31125 while(p && p != el){
31126 if(p.parentNode == el){
31135 onClick : function(e){
31136 var item = this.findItemFromChild(e.getTarget());
31138 var index = this.indexOf(item);
31139 if(this.onItemClick(item, index, e) !== false){
31140 this.fireEvent("click", this, index, item, e);
31143 this.clearSelections();
31148 onContextMenu : function(e){
31149 var item = this.findItemFromChild(e.getTarget());
31151 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
31156 onDblClick : function(e){
31157 var item = this.findItemFromChild(e.getTarget());
31159 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
31163 onItemClick : function(item, index, e)
31165 if(this.fireEvent("beforeclick", this, index, item, e) === false){
31168 if (this.toggleSelect) {
31169 var m = this.isSelected(item) ? 'unselect' : 'select';
31172 _t[m](item, true, false);
31175 if(this.multiSelect || this.singleSelect){
31176 if(this.multiSelect && e.shiftKey && this.lastSelection){
31177 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
31179 this.select(item, this.multiSelect && e.ctrlKey);
31180 this.lastSelection = item;
31183 if(!this.tickable){
31184 e.preventDefault();
31192 * Get the number of selected nodes.
31195 getSelectionCount : function(){
31196 return this.selections.length;
31200 * Get the currently selected nodes.
31201 * @return {Array} An array of HTMLElements
31203 getSelectedNodes : function(){
31204 return this.selections;
31208 * Get the indexes of the selected nodes.
31211 getSelectedIndexes : function(){
31212 var indexes = [], s = this.selections;
31213 for(var i = 0, len = s.length; i < len; i++){
31214 indexes.push(s[i].nodeIndex);
31220 * Clear all selections
31221 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
31223 clearSelections : function(suppressEvent){
31224 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
31225 this.cmp.elements = this.selections;
31226 this.cmp.removeClass(this.selectedClass);
31227 this.selections = [];
31228 if(!suppressEvent){
31229 this.fireEvent("selectionchange", this, this.selections);
31235 * Returns true if the passed node is selected
31236 * @param {HTMLElement/Number} node The node or node index
31237 * @return {Boolean}
31239 isSelected : function(node){
31240 var s = this.selections;
31244 node = this.getNode(node);
31245 return s.indexOf(node) !== -1;
31250 * @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
31251 * @param {Boolean} keepExisting (optional) true to keep existing selections
31252 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
31254 select : function(nodeInfo, keepExisting, suppressEvent){
31255 if(nodeInfo instanceof Array){
31257 this.clearSelections(true);
31259 for(var i = 0, len = nodeInfo.length; i < len; i++){
31260 this.select(nodeInfo[i], true, true);
31264 var node = this.getNode(nodeInfo);
31265 if(!node || this.isSelected(node)){
31266 return; // already selected.
31269 this.clearSelections(true);
31272 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
31273 Roo.fly(node).addClass(this.selectedClass);
31274 this.selections.push(node);
31275 if(!suppressEvent){
31276 this.fireEvent("selectionchange", this, this.selections);
31284 * @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
31285 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
31286 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
31288 unselect : function(nodeInfo, keepExisting, suppressEvent)
31290 if(nodeInfo instanceof Array){
31291 Roo.each(this.selections, function(s) {
31292 this.unselect(s, nodeInfo);
31296 var node = this.getNode(nodeInfo);
31297 if(!node || !this.isSelected(node)){
31298 //Roo.log("not selected");
31299 return; // not selected.
31303 Roo.each(this.selections, function(s) {
31305 Roo.fly(node).removeClass(this.selectedClass);
31312 this.selections= ns;
31313 this.fireEvent("selectionchange", this, this.selections);
31317 * Gets a template node.
31318 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
31319 * @return {HTMLElement} The node or null if it wasn't found
31321 getNode : function(nodeInfo){
31322 if(typeof nodeInfo == "string"){
31323 return document.getElementById(nodeInfo);
31324 }else if(typeof nodeInfo == "number"){
31325 return this.nodes[nodeInfo];
31331 * Gets a range template nodes.
31332 * @param {Number} startIndex
31333 * @param {Number} endIndex
31334 * @return {Array} An array of nodes
31336 getNodes : function(start, end){
31337 var ns = this.nodes;
31338 start = start || 0;
31339 end = typeof end == "undefined" ? ns.length - 1 : end;
31342 for(var i = start; i <= end; i++){
31346 for(var i = start; i >= end; i--){
31354 * Finds the index of the passed node
31355 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
31356 * @return {Number} The index of the node or -1
31358 indexOf : function(node){
31359 node = this.getNode(node);
31360 if(typeof node.nodeIndex == "number"){
31361 return node.nodeIndex;
31363 var ns = this.nodes;
31364 for(var i = 0, len = ns.length; i < len; i++){
31374 * Ext JS Library 1.1.1
31375 * Copyright(c) 2006-2007, Ext JS, LLC.
31377 * Originally Released Under LGPL - original licence link has changed is not relivant.
31380 * <script type="text/javascript">
31384 * @class Roo.JsonView
31385 * @extends Roo.View
31386 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
31388 var view = new Roo.JsonView({
31389 container: "my-element",
31390 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
31395 // listen for node click?
31396 view.on("click", function(vw, index, node, e){
31397 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
31400 // direct load of JSON data
31401 view.load("foobar.php");
31403 // Example from my blog list
31404 var tpl = new Roo.Template(
31405 '<div class="entry">' +
31406 '<a class="entry-title" href="{link}">{title}</a>' +
31407 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
31408 "</div><hr />"
31411 var moreView = new Roo.JsonView({
31412 container : "entry-list",
31416 moreView.on("beforerender", this.sortEntries, this);
31418 url: "/blog/get-posts.php",
31419 params: "allposts=true",
31420 text: "Loading Blog Entries..."
31424 * Note: old code is supported with arguments : (container, template, config)
31428 * Create a new JsonView
31430 * @param {Object} config The config object
31433 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
31436 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
31438 var um = this.el.getUpdateManager();
31439 um.setRenderer(this);
31440 um.on("update", this.onLoad, this);
31441 um.on("failure", this.onLoadException, this);
31444 * @event beforerender
31445 * Fires before rendering of the downloaded JSON data.
31446 * @param {Roo.JsonView} this
31447 * @param {Object} data The JSON data loaded
31451 * Fires when data is loaded.
31452 * @param {Roo.JsonView} this
31453 * @param {Object} data The JSON data loaded
31454 * @param {Object} response The raw Connect response object
31457 * @event loadexception
31458 * Fires when loading fails.
31459 * @param {Roo.JsonView} this
31460 * @param {Object} response The raw Connect response object
31463 'beforerender' : true,
31465 'loadexception' : true
31468 Roo.extend(Roo.JsonView, Roo.View, {
31470 * @type {String} The root property in the loaded JSON object that contains the data
31475 * Refreshes the view.
31477 refresh : function(){
31478 this.clearSelections();
31479 this.el.update("");
31481 var o = this.jsonData;
31482 if(o && o.length > 0){
31483 for(var i = 0, len = o.length; i < len; i++){
31484 var data = this.prepareData(o[i], i, o);
31485 html[html.length] = this.tpl.apply(data);
31488 html.push(this.emptyText);
31490 this.el.update(html.join(""));
31491 this.nodes = this.el.dom.childNodes;
31492 this.updateIndexes(0);
31496 * 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.
31497 * @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:
31500 url: "your-url.php",
31501 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
31502 callback: yourFunction,
31503 scope: yourObject, //(optional scope)
31506 text: "Loading...",
31511 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
31512 * 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.
31513 * @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}
31514 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
31515 * @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.
31518 var um = this.el.getUpdateManager();
31519 um.update.apply(um, arguments);
31522 // note - render is a standard framework call...
31523 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
31524 render : function(el, response){
31526 this.clearSelections();
31527 this.el.update("");
31530 if (response != '') {
31531 o = Roo.util.JSON.decode(response.responseText);
31534 o = o[this.jsonRoot];
31540 * The current JSON data or null
31543 this.beforeRender();
31548 * Get the number of records in the current JSON dataset
31551 getCount : function(){
31552 return this.jsonData ? this.jsonData.length : 0;
31556 * Returns the JSON object for the specified node(s)
31557 * @param {HTMLElement/Array} node The node or an array of nodes
31558 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
31559 * you get the JSON object for the node
31561 getNodeData : function(node){
31562 if(node instanceof Array){
31564 for(var i = 0, len = node.length; i < len; i++){
31565 data.push(this.getNodeData(node[i]));
31569 return this.jsonData[this.indexOf(node)] || null;
31572 beforeRender : function(){
31573 this.snapshot = this.jsonData;
31575 this.sort.apply(this, this.sortInfo);
31577 this.fireEvent("beforerender", this, this.jsonData);
31580 onLoad : function(el, o){
31581 this.fireEvent("load", this, this.jsonData, o);
31584 onLoadException : function(el, o){
31585 this.fireEvent("loadexception", this, o);
31589 * Filter the data by a specific property.
31590 * @param {String} property A property on your JSON objects
31591 * @param {String/RegExp} value Either string that the property values
31592 * should start with, or a RegExp to test against the property
31594 filter : function(property, value){
31597 var ss = this.snapshot;
31598 if(typeof value == "string"){
31599 var vlen = value.length;
31601 this.clearFilter();
31604 value = value.toLowerCase();
31605 for(var i = 0, len = ss.length; i < len; i++){
31607 if(o[property].substr(0, vlen).toLowerCase() == value){
31611 } else if(value.exec){ // regex?
31612 for(var i = 0, len = ss.length; i < len; i++){
31614 if(value.test(o[property])){
31621 this.jsonData = data;
31627 * Filter by a function. The passed function will be called with each
31628 * object in the current dataset. If the function returns true the value is kept,
31629 * otherwise it is filtered.
31630 * @param {Function} fn
31631 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
31633 filterBy : function(fn, scope){
31636 var ss = this.snapshot;
31637 for(var i = 0, len = ss.length; i < len; i++){
31639 if(fn.call(scope || this, o)){
31643 this.jsonData = data;
31649 * Clears the current filter.
31651 clearFilter : function(){
31652 if(this.snapshot && this.jsonData != this.snapshot){
31653 this.jsonData = this.snapshot;
31660 * Sorts the data for this view and refreshes it.
31661 * @param {String} property A property on your JSON objects to sort on
31662 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
31663 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
31665 sort : function(property, dir, sortType){
31666 this.sortInfo = Array.prototype.slice.call(arguments, 0);
31669 var dsc = dir && dir.toLowerCase() == "desc";
31670 var f = function(o1, o2){
31671 var v1 = sortType ? sortType(o1[p]) : o1[p];
31672 var v2 = sortType ? sortType(o2[p]) : o2[p];
31675 return dsc ? +1 : -1;
31676 } else if(v1 > v2){
31677 return dsc ? -1 : +1;
31682 this.jsonData.sort(f);
31684 if(this.jsonData != this.snapshot){
31685 this.snapshot.sort(f);
31691 * Ext JS Library 1.1.1
31692 * Copyright(c) 2006-2007, Ext JS, LLC.
31694 * Originally Released Under LGPL - original licence link has changed is not relivant.
31697 * <script type="text/javascript">
31702 * @class Roo.ColorPalette
31703 * @extends Roo.Component
31704 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
31705 * Here's an example of typical usage:
31707 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
31708 cp.render('my-div');
31710 cp.on('select', function(palette, selColor){
31711 // do something with selColor
31715 * Create a new ColorPalette
31716 * @param {Object} config The config object
31718 Roo.ColorPalette = function(config){
31719 Roo.ColorPalette.superclass.constructor.call(this, config);
31723 * Fires when a color is selected
31724 * @param {ColorPalette} this
31725 * @param {String} color The 6-digit color hex code (without the # symbol)
31731 this.on("select", this.handler, this.scope, true);
31734 Roo.extend(Roo.ColorPalette, Roo.Component, {
31736 * @cfg {String} itemCls
31737 * The CSS class to apply to the containing element (defaults to "x-color-palette")
31739 itemCls : "x-color-palette",
31741 * @cfg {String} value
31742 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
31743 * the hex codes are case-sensitive.
31746 clickEvent:'click',
31748 ctype: "Roo.ColorPalette",
31751 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
31753 allowReselect : false,
31756 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
31757 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
31758 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
31759 * of colors with the width setting until the box is symmetrical.</p>
31760 * <p>You can override individual colors if needed:</p>
31762 var cp = new Roo.ColorPalette();
31763 cp.colors[0] = "FF0000"; // change the first box to red
31766 Or you can provide a custom array of your own for complete control:
31768 var cp = new Roo.ColorPalette();
31769 cp.colors = ["000000", "993300", "333300"];
31774 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
31775 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
31776 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
31777 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
31778 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
31782 onRender : function(container, position){
31783 var t = new Roo.MasterTemplate(
31784 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
31786 var c = this.colors;
31787 for(var i = 0, len = c.length; i < len; i++){
31790 var el = document.createElement("div");
31791 el.className = this.itemCls;
31793 container.dom.insertBefore(el, position);
31794 this.el = Roo.get(el);
31795 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
31796 if(this.clickEvent != 'click'){
31797 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
31802 afterRender : function(){
31803 Roo.ColorPalette.superclass.afterRender.call(this);
31805 var s = this.value;
31812 handleClick : function(e, t){
31813 e.preventDefault();
31814 if(!this.disabled){
31815 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
31816 this.select(c.toUpperCase());
31821 * Selects the specified color in the palette (fires the select event)
31822 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
31824 select : function(color){
31825 color = color.replace("#", "");
31826 if(color != this.value || this.allowReselect){
31829 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
31831 el.child("a.color-"+color).addClass("x-color-palette-sel");
31832 this.value = color;
31833 this.fireEvent("select", this, color);
31838 * Ext JS Library 1.1.1
31839 * Copyright(c) 2006-2007, Ext JS, LLC.
31841 * Originally Released Under LGPL - original licence link has changed is not relivant.
31844 * <script type="text/javascript">
31848 * @class Roo.DatePicker
31849 * @extends Roo.Component
31850 * Simple date picker class.
31852 * Create a new DatePicker
31853 * @param {Object} config The config object
31855 Roo.DatePicker = function(config){
31856 Roo.DatePicker.superclass.constructor.call(this, config);
31858 this.value = config && config.value ?
31859 config.value.clearTime() : new Date().clearTime();
31864 * Fires when a date is selected
31865 * @param {DatePicker} this
31866 * @param {Date} date The selected date
31870 * @event monthchange
31871 * Fires when the displayed month changes
31872 * @param {DatePicker} this
31873 * @param {Date} date The selected month
31875 'monthchange': true
31879 this.on("select", this.handler, this.scope || this);
31881 // build the disabledDatesRE
31882 if(!this.disabledDatesRE && this.disabledDates){
31883 var dd = this.disabledDates;
31885 for(var i = 0; i < dd.length; i++){
31887 if(i != dd.length-1) {
31891 this.disabledDatesRE = new RegExp(re + ")");
31895 Roo.extend(Roo.DatePicker, Roo.Component, {
31897 * @cfg {String} todayText
31898 * The text to display on the button that selects the current date (defaults to "Today")
31900 todayText : "Today",
31902 * @cfg {String} okText
31903 * The text to display on the ok button
31905 okText : " OK ", //   to give the user extra clicking room
31907 * @cfg {String} cancelText
31908 * The text to display on the cancel button
31910 cancelText : "Cancel",
31912 * @cfg {String} todayTip
31913 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
31915 todayTip : "{0} (Spacebar)",
31917 * @cfg {Date} minDate
31918 * Minimum allowable date (JavaScript date object, defaults to null)
31922 * @cfg {Date} maxDate
31923 * Maximum allowable date (JavaScript date object, defaults to null)
31927 * @cfg {String} minText
31928 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
31930 minText : "This date is before the minimum date",
31932 * @cfg {String} maxText
31933 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
31935 maxText : "This date is after the maximum date",
31937 * @cfg {String} format
31938 * The default date format string which can be overriden for localization support. The format must be
31939 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
31943 * @cfg {Array} disabledDays
31944 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
31946 disabledDays : null,
31948 * @cfg {String} disabledDaysText
31949 * The tooltip to display when the date falls on a disabled day (defaults to "")
31951 disabledDaysText : "",
31953 * @cfg {RegExp} disabledDatesRE
31954 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
31956 disabledDatesRE : null,
31958 * @cfg {String} disabledDatesText
31959 * The tooltip text to display when the date falls on a disabled date (defaults to "")
31961 disabledDatesText : "",
31963 * @cfg {Boolean} constrainToViewport
31964 * True to constrain the date picker to the viewport (defaults to true)
31966 constrainToViewport : true,
31968 * @cfg {Array} monthNames
31969 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
31971 monthNames : Date.monthNames,
31973 * @cfg {Array} dayNames
31974 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
31976 dayNames : Date.dayNames,
31978 * @cfg {String} nextText
31979 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
31981 nextText: 'Next Month (Control+Right)',
31983 * @cfg {String} prevText
31984 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
31986 prevText: 'Previous Month (Control+Left)',
31988 * @cfg {String} monthYearText
31989 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
31991 monthYearText: 'Choose a month (Control+Up/Down to move years)',
31993 * @cfg {Number} startDay
31994 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
31998 * @cfg {Bool} showClear
31999 * Show a clear button (usefull for date form elements that can be blank.)
32005 * Sets the value of the date field
32006 * @param {Date} value The date to set
32008 setValue : function(value){
32009 var old = this.value;
32011 if (typeof(value) == 'string') {
32013 value = Date.parseDate(value, this.format);
32016 value = new Date();
32019 this.value = value.clearTime(true);
32021 this.update(this.value);
32026 * Gets the current selected value of the date field
32027 * @return {Date} The selected date
32029 getValue : function(){
32034 focus : function(){
32036 this.update(this.activeDate);
32041 onRender : function(container, position){
32044 '<table cellspacing="0">',
32045 '<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>',
32046 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
32047 var dn = this.dayNames;
32048 for(var i = 0; i < 7; i++){
32049 var d = this.startDay+i;
32053 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
32055 m[m.length] = "</tr></thead><tbody><tr>";
32056 for(var i = 0; i < 42; i++) {
32057 if(i % 7 == 0 && i != 0){
32058 m[m.length] = "</tr><tr>";
32060 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
32062 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
32063 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
32065 var el = document.createElement("div");
32066 el.className = "x-date-picker";
32067 el.innerHTML = m.join("");
32069 container.dom.insertBefore(el, position);
32071 this.el = Roo.get(el);
32072 this.eventEl = Roo.get(el.firstChild);
32074 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
32075 handler: this.showPrevMonth,
32077 preventDefault:true,
32081 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
32082 handler: this.showNextMonth,
32084 preventDefault:true,
32088 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
32090 this.monthPicker = this.el.down('div.x-date-mp');
32091 this.monthPicker.enableDisplayMode('block');
32093 var kn = new Roo.KeyNav(this.eventEl, {
32094 "left" : function(e){
32096 this.showPrevMonth() :
32097 this.update(this.activeDate.add("d", -1));
32100 "right" : function(e){
32102 this.showNextMonth() :
32103 this.update(this.activeDate.add("d", 1));
32106 "up" : function(e){
32108 this.showNextYear() :
32109 this.update(this.activeDate.add("d", -7));
32112 "down" : function(e){
32114 this.showPrevYear() :
32115 this.update(this.activeDate.add("d", 7));
32118 "pageUp" : function(e){
32119 this.showNextMonth();
32122 "pageDown" : function(e){
32123 this.showPrevMonth();
32126 "enter" : function(e){
32127 e.stopPropagation();
32134 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
32136 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
32138 this.el.unselectable();
32140 this.cells = this.el.select("table.x-date-inner tbody td");
32141 this.textNodes = this.el.query("table.x-date-inner tbody span");
32143 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
32145 tooltip: this.monthYearText
32148 this.mbtn.on('click', this.showMonthPicker, this);
32149 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
32152 var today = (new Date()).dateFormat(this.format);
32154 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
32155 if (this.showClear) {
32156 baseTb.add( new Roo.Toolbar.Fill());
32159 text: String.format(this.todayText, today),
32160 tooltip: String.format(this.todayTip, today),
32161 handler: this.selectToday,
32165 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
32168 if (this.showClear) {
32170 baseTb.add( new Roo.Toolbar.Fill());
32173 cls: 'x-btn-icon x-btn-clear',
32174 handler: function() {
32176 this.fireEvent("select", this, '');
32186 this.update(this.value);
32189 createMonthPicker : function(){
32190 if(!this.monthPicker.dom.firstChild){
32191 var buf = ['<table border="0" cellspacing="0">'];
32192 for(var i = 0; i < 6; i++){
32194 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
32195 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
32197 '<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>' :
32198 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
32202 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
32204 '</button><button type="button" class="x-date-mp-cancel">',
32206 '</button></td></tr>',
32209 this.monthPicker.update(buf.join(''));
32210 this.monthPicker.on('click', this.onMonthClick, this);
32211 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
32213 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
32214 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
32216 this.mpMonths.each(function(m, a, i){
32219 m.dom.xmonth = 5 + Math.round(i * .5);
32221 m.dom.xmonth = Math.round((i-1) * .5);
32227 showMonthPicker : function(){
32228 this.createMonthPicker();
32229 var size = this.el.getSize();
32230 this.monthPicker.setSize(size);
32231 this.monthPicker.child('table').setSize(size);
32233 this.mpSelMonth = (this.activeDate || this.value).getMonth();
32234 this.updateMPMonth(this.mpSelMonth);
32235 this.mpSelYear = (this.activeDate || this.value).getFullYear();
32236 this.updateMPYear(this.mpSelYear);
32238 this.monthPicker.slideIn('t', {duration:.2});
32241 updateMPYear : function(y){
32243 var ys = this.mpYears.elements;
32244 for(var i = 1; i <= 10; i++){
32245 var td = ys[i-1], y2;
32247 y2 = y + Math.round(i * .5);
32248 td.firstChild.innerHTML = y2;
32251 y2 = y - (5-Math.round(i * .5));
32252 td.firstChild.innerHTML = y2;
32255 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
32259 updateMPMonth : function(sm){
32260 this.mpMonths.each(function(m, a, i){
32261 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
32265 selectMPMonth: function(m){
32269 onMonthClick : function(e, t){
32271 var el = new Roo.Element(t), pn;
32272 if(el.is('button.x-date-mp-cancel')){
32273 this.hideMonthPicker();
32275 else if(el.is('button.x-date-mp-ok')){
32276 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
32277 this.hideMonthPicker();
32279 else if(pn = el.up('td.x-date-mp-month', 2)){
32280 this.mpMonths.removeClass('x-date-mp-sel');
32281 pn.addClass('x-date-mp-sel');
32282 this.mpSelMonth = pn.dom.xmonth;
32284 else if(pn = el.up('td.x-date-mp-year', 2)){
32285 this.mpYears.removeClass('x-date-mp-sel');
32286 pn.addClass('x-date-mp-sel');
32287 this.mpSelYear = pn.dom.xyear;
32289 else if(el.is('a.x-date-mp-prev')){
32290 this.updateMPYear(this.mpyear-10);
32292 else if(el.is('a.x-date-mp-next')){
32293 this.updateMPYear(this.mpyear+10);
32297 onMonthDblClick : function(e, t){
32299 var el = new Roo.Element(t), pn;
32300 if(pn = el.up('td.x-date-mp-month', 2)){
32301 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
32302 this.hideMonthPicker();
32304 else if(pn = el.up('td.x-date-mp-year', 2)){
32305 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
32306 this.hideMonthPicker();
32310 hideMonthPicker : function(disableAnim){
32311 if(this.monthPicker){
32312 if(disableAnim === true){
32313 this.monthPicker.hide();
32315 this.monthPicker.slideOut('t', {duration:.2});
32321 showPrevMonth : function(e){
32322 this.update(this.activeDate.add("mo", -1));
32326 showNextMonth : function(e){
32327 this.update(this.activeDate.add("mo", 1));
32331 showPrevYear : function(){
32332 this.update(this.activeDate.add("y", -1));
32336 showNextYear : function(){
32337 this.update(this.activeDate.add("y", 1));
32341 handleMouseWheel : function(e){
32342 var delta = e.getWheelDelta();
32344 this.showPrevMonth();
32346 } else if(delta < 0){
32347 this.showNextMonth();
32353 handleDateClick : function(e, t){
32355 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
32356 this.setValue(new Date(t.dateValue));
32357 this.fireEvent("select", this, this.value);
32362 selectToday : function(){
32363 this.setValue(new Date().clearTime());
32364 this.fireEvent("select", this, this.value);
32368 update : function(date)
32370 var vd = this.activeDate;
32371 this.activeDate = date;
32373 var t = date.getTime();
32374 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
32375 this.cells.removeClass("x-date-selected");
32376 this.cells.each(function(c){
32377 if(c.dom.firstChild.dateValue == t){
32378 c.addClass("x-date-selected");
32379 setTimeout(function(){
32380 try{c.dom.firstChild.focus();}catch(e){}
32389 var days = date.getDaysInMonth();
32390 var firstOfMonth = date.getFirstDateOfMonth();
32391 var startingPos = firstOfMonth.getDay()-this.startDay;
32393 if(startingPos <= this.startDay){
32397 var pm = date.add("mo", -1);
32398 var prevStart = pm.getDaysInMonth()-startingPos;
32400 var cells = this.cells.elements;
32401 var textEls = this.textNodes;
32402 days += startingPos;
32404 // convert everything to numbers so it's fast
32405 var day = 86400000;
32406 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
32407 var today = new Date().clearTime().getTime();
32408 var sel = date.clearTime().getTime();
32409 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
32410 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
32411 var ddMatch = this.disabledDatesRE;
32412 var ddText = this.disabledDatesText;
32413 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
32414 var ddaysText = this.disabledDaysText;
32415 var format = this.format;
32417 var setCellClass = function(cal, cell){
32419 var t = d.getTime();
32420 cell.firstChild.dateValue = t;
32422 cell.className += " x-date-today";
32423 cell.title = cal.todayText;
32426 cell.className += " x-date-selected";
32427 setTimeout(function(){
32428 try{cell.firstChild.focus();}catch(e){}
32433 cell.className = " x-date-disabled";
32434 cell.title = cal.minText;
32438 cell.className = " x-date-disabled";
32439 cell.title = cal.maxText;
32443 if(ddays.indexOf(d.getDay()) != -1){
32444 cell.title = ddaysText;
32445 cell.className = " x-date-disabled";
32448 if(ddMatch && format){
32449 var fvalue = d.dateFormat(format);
32450 if(ddMatch.test(fvalue)){
32451 cell.title = ddText.replace("%0", fvalue);
32452 cell.className = " x-date-disabled";
32458 for(; i < startingPos; i++) {
32459 textEls[i].innerHTML = (++prevStart);
32460 d.setDate(d.getDate()+1);
32461 cells[i].className = "x-date-prevday";
32462 setCellClass(this, cells[i]);
32464 for(; i < days; i++){
32465 intDay = i - startingPos + 1;
32466 textEls[i].innerHTML = (intDay);
32467 d.setDate(d.getDate()+1);
32468 cells[i].className = "x-date-active";
32469 setCellClass(this, cells[i]);
32472 for(; i < 42; i++) {
32473 textEls[i].innerHTML = (++extraDays);
32474 d.setDate(d.getDate()+1);
32475 cells[i].className = "x-date-nextday";
32476 setCellClass(this, cells[i]);
32479 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
32480 this.fireEvent('monthchange', this, date);
32482 if(!this.internalRender){
32483 var main = this.el.dom.firstChild;
32484 var w = main.offsetWidth;
32485 this.el.setWidth(w + this.el.getBorderWidth("lr"));
32486 Roo.fly(main).setWidth(w);
32487 this.internalRender = true;
32488 // opera does not respect the auto grow header center column
32489 // then, after it gets a width opera refuses to recalculate
32490 // without a second pass
32491 if(Roo.isOpera && !this.secondPass){
32492 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
32493 this.secondPass = true;
32494 this.update.defer(10, this, [date]);
32502 * Ext JS Library 1.1.1
32503 * Copyright(c) 2006-2007, Ext JS, LLC.
32505 * Originally Released Under LGPL - original licence link has changed is not relivant.
32508 * <script type="text/javascript">
32511 * @class Roo.TabPanel
32512 * @extends Roo.util.Observable
32513 * A lightweight tab container.
32517 // basic tabs 1, built from existing content
32518 var tabs = new Roo.TabPanel("tabs1");
32519 tabs.addTab("script", "View Script");
32520 tabs.addTab("markup", "View Markup");
32521 tabs.activate("script");
32523 // more advanced tabs, built from javascript
32524 var jtabs = new Roo.TabPanel("jtabs");
32525 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
32527 // set up the UpdateManager
32528 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
32529 var updater = tab2.getUpdateManager();
32530 updater.setDefaultUrl("ajax1.htm");
32531 tab2.on('activate', updater.refresh, updater, true);
32533 // Use setUrl for Ajax loading
32534 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
32535 tab3.setUrl("ajax2.htm", null, true);
32538 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
32541 jtabs.activate("jtabs-1");
32544 * Create a new TabPanel.
32545 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
32546 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
32548 Roo.TabPanel = function(container, config){
32550 * The container element for this TabPanel.
32551 * @type Roo.Element
32553 this.el = Roo.get(container, true);
32555 if(typeof config == "boolean"){
32556 this.tabPosition = config ? "bottom" : "top";
32558 Roo.apply(this, config);
32561 if(this.tabPosition == "bottom"){
32562 this.bodyEl = Roo.get(this.createBody(this.el.dom));
32563 this.el.addClass("x-tabs-bottom");
32565 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
32566 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
32567 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
32569 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
32571 if(this.tabPosition != "bottom"){
32572 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
32573 * @type Roo.Element
32575 this.bodyEl = Roo.get(this.createBody(this.el.dom));
32576 this.el.addClass("x-tabs-top");
32580 this.bodyEl.setStyle("position", "relative");
32582 this.active = null;
32583 this.activateDelegate = this.activate.createDelegate(this);
32588 * Fires when the active tab changes
32589 * @param {Roo.TabPanel} this
32590 * @param {Roo.TabPanelItem} activePanel The new active tab
32594 * @event beforetabchange
32595 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
32596 * @param {Roo.TabPanel} this
32597 * @param {Object} e Set cancel to true on this object to cancel the tab change
32598 * @param {Roo.TabPanelItem} tab The tab being changed to
32600 "beforetabchange" : true
32603 Roo.EventManager.onWindowResize(this.onResize, this);
32604 this.cpad = this.el.getPadding("lr");
32605 this.hiddenCount = 0;
32608 // toolbar on the tabbar support...
32609 if (this.toolbar) {
32610 var tcfg = this.toolbar;
32611 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
32612 this.toolbar = new Roo.Toolbar(tcfg);
32613 if (Roo.isSafari) {
32614 var tbl = tcfg.container.child('table', true);
32615 tbl.setAttribute('width', '100%');
32622 Roo.TabPanel.superclass.constructor.call(this);
32625 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
32627 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
32629 tabPosition : "top",
32631 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
32633 currentTabWidth : 0,
32635 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
32639 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
32643 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
32645 preferredTabWidth : 175,
32647 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
32649 resizeTabs : false,
32651 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
32653 monitorResize : true,
32655 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
32660 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
32661 * @param {String} id The id of the div to use <b>or create</b>
32662 * @param {String} text The text for the tab
32663 * @param {String} content (optional) Content to put in the TabPanelItem body
32664 * @param {Boolean} closable (optional) True to create a close icon on the tab
32665 * @return {Roo.TabPanelItem} The created TabPanelItem
32667 addTab : function(id, text, content, closable){
32668 var item = new Roo.TabPanelItem(this, id, text, closable);
32669 this.addTabItem(item);
32671 item.setContent(content);
32677 * Returns the {@link Roo.TabPanelItem} with the specified id/index
32678 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
32679 * @return {Roo.TabPanelItem}
32681 getTab : function(id){
32682 return this.items[id];
32686 * Hides the {@link Roo.TabPanelItem} with the specified id/index
32687 * @param {String/Number} id The id or index of the TabPanelItem to hide.
32689 hideTab : function(id){
32690 var t = this.items[id];
32693 this.hiddenCount++;
32694 this.autoSizeTabs();
32699 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
32700 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
32702 unhideTab : function(id){
32703 var t = this.items[id];
32705 t.setHidden(false);
32706 this.hiddenCount--;
32707 this.autoSizeTabs();
32712 * Adds an existing {@link Roo.TabPanelItem}.
32713 * @param {Roo.TabPanelItem} item The TabPanelItem to add
32715 addTabItem : function(item){
32716 this.items[item.id] = item;
32717 this.items.push(item);
32718 if(this.resizeTabs){
32719 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
32720 this.autoSizeTabs();
32727 * Removes a {@link Roo.TabPanelItem}.
32728 * @param {String/Number} id The id or index of the TabPanelItem to remove.
32730 removeTab : function(id){
32731 var items = this.items;
32732 var tab = items[id];
32733 if(!tab) { return; }
32734 var index = items.indexOf(tab);
32735 if(this.active == tab && items.length > 1){
32736 var newTab = this.getNextAvailable(index);
32741 this.stripEl.dom.removeChild(tab.pnode.dom);
32742 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
32743 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
32745 items.splice(index, 1);
32746 delete this.items[tab.id];
32747 tab.fireEvent("close", tab);
32748 tab.purgeListeners();
32749 this.autoSizeTabs();
32752 getNextAvailable : function(start){
32753 var items = this.items;
32755 // look for a next tab that will slide over to
32756 // replace the one being removed
32757 while(index < items.length){
32758 var item = items[++index];
32759 if(item && !item.isHidden()){
32763 // if one isn't found select the previous tab (on the left)
32766 var item = items[--index];
32767 if(item && !item.isHidden()){
32775 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
32776 * @param {String/Number} id The id or index of the TabPanelItem to disable.
32778 disableTab : function(id){
32779 var tab = this.items[id];
32780 if(tab && this.active != tab){
32786 * Enables a {@link Roo.TabPanelItem} that is disabled.
32787 * @param {String/Number} id The id or index of the TabPanelItem to enable.
32789 enableTab : function(id){
32790 var tab = this.items[id];
32795 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
32796 * @param {String/Number} id The id or index of the TabPanelItem to activate.
32797 * @return {Roo.TabPanelItem} The TabPanelItem.
32799 activate : function(id){
32800 var tab = this.items[id];
32804 if(tab == this.active || tab.disabled){
32808 this.fireEvent("beforetabchange", this, e, tab);
32809 if(e.cancel !== true && !tab.disabled){
32811 this.active.hide();
32813 this.active = this.items[id];
32814 this.active.show();
32815 this.fireEvent("tabchange", this, this.active);
32821 * Gets the active {@link Roo.TabPanelItem}.
32822 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
32824 getActiveTab : function(){
32825 return this.active;
32829 * Updates the tab body element to fit the height of the container element
32830 * for overflow scrolling
32831 * @param {Number} targetHeight (optional) Override the starting height from the elements height
32833 syncHeight : function(targetHeight){
32834 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
32835 var bm = this.bodyEl.getMargins();
32836 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
32837 this.bodyEl.setHeight(newHeight);
32841 onResize : function(){
32842 if(this.monitorResize){
32843 this.autoSizeTabs();
32848 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
32850 beginUpdate : function(){
32851 this.updating = true;
32855 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
32857 endUpdate : function(){
32858 this.updating = false;
32859 this.autoSizeTabs();
32863 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
32865 autoSizeTabs : function(){
32866 var count = this.items.length;
32867 var vcount = count - this.hiddenCount;
32868 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
32871 var w = Math.max(this.el.getWidth() - this.cpad, 10);
32872 var availWidth = Math.floor(w / vcount);
32873 var b = this.stripBody;
32874 if(b.getWidth() > w){
32875 var tabs = this.items;
32876 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
32877 if(availWidth < this.minTabWidth){
32878 /*if(!this.sleft){ // incomplete scrolling code
32879 this.createScrollButtons();
32882 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
32885 if(this.currentTabWidth < this.preferredTabWidth){
32886 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
32892 * Returns the number of tabs in this TabPanel.
32895 getCount : function(){
32896 return this.items.length;
32900 * Resizes all the tabs to the passed width
32901 * @param {Number} The new width
32903 setTabWidth : function(width){
32904 this.currentTabWidth = width;
32905 for(var i = 0, len = this.items.length; i < len; i++) {
32906 if(!this.items[i].isHidden()) {
32907 this.items[i].setWidth(width);
32913 * Destroys this TabPanel
32914 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
32916 destroy : function(removeEl){
32917 Roo.EventManager.removeResizeListener(this.onResize, this);
32918 for(var i = 0, len = this.items.length; i < len; i++){
32919 this.items[i].purgeListeners();
32921 if(removeEl === true){
32922 this.el.update("");
32929 * @class Roo.TabPanelItem
32930 * @extends Roo.util.Observable
32931 * Represents an individual item (tab plus body) in a TabPanel.
32932 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
32933 * @param {String} id The id of this TabPanelItem
32934 * @param {String} text The text for the tab of this TabPanelItem
32935 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
32937 Roo.TabPanelItem = function(tabPanel, id, text, closable){
32939 * The {@link Roo.TabPanel} this TabPanelItem belongs to
32940 * @type Roo.TabPanel
32942 this.tabPanel = tabPanel;
32944 * The id for this TabPanelItem
32949 this.disabled = false;
32953 this.loaded = false;
32954 this.closable = closable;
32957 * The body element for this TabPanelItem.
32958 * @type Roo.Element
32960 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
32961 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
32962 this.bodyEl.setStyle("display", "block");
32963 this.bodyEl.setStyle("zoom", "1");
32966 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
32968 this.el = Roo.get(els.el, true);
32969 this.inner = Roo.get(els.inner, true);
32970 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
32971 this.pnode = Roo.get(els.el.parentNode, true);
32972 this.el.on("mousedown", this.onTabMouseDown, this);
32973 this.el.on("click", this.onTabClick, this);
32976 var c = Roo.get(els.close, true);
32977 c.dom.title = this.closeText;
32978 c.addClassOnOver("close-over");
32979 c.on("click", this.closeClick, this);
32985 * Fires when this tab becomes the active tab.
32986 * @param {Roo.TabPanel} tabPanel The parent TabPanel
32987 * @param {Roo.TabPanelItem} this
32991 * @event beforeclose
32992 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
32993 * @param {Roo.TabPanelItem} this
32994 * @param {Object} e Set cancel to true on this object to cancel the close.
32996 "beforeclose": true,
32999 * Fires when this tab is closed.
33000 * @param {Roo.TabPanelItem} this
33004 * @event deactivate
33005 * Fires when this tab is no longer the active tab.
33006 * @param {Roo.TabPanel} tabPanel The parent TabPanel
33007 * @param {Roo.TabPanelItem} this
33009 "deactivate" : true
33011 this.hidden = false;
33013 Roo.TabPanelItem.superclass.constructor.call(this);
33016 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
33017 purgeListeners : function(){
33018 Roo.util.Observable.prototype.purgeListeners.call(this);
33019 this.el.removeAllListeners();
33022 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
33025 this.pnode.addClass("on");
33028 this.tabPanel.stripWrap.repaint();
33030 this.fireEvent("activate", this.tabPanel, this);
33034 * Returns true if this tab is the active tab.
33035 * @return {Boolean}
33037 isActive : function(){
33038 return this.tabPanel.getActiveTab() == this;
33042 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
33045 this.pnode.removeClass("on");
33047 this.fireEvent("deactivate", this.tabPanel, this);
33050 hideAction : function(){
33051 this.bodyEl.hide();
33052 this.bodyEl.setStyle("position", "absolute");
33053 this.bodyEl.setLeft("-20000px");
33054 this.bodyEl.setTop("-20000px");
33057 showAction : function(){
33058 this.bodyEl.setStyle("position", "relative");
33059 this.bodyEl.setTop("");
33060 this.bodyEl.setLeft("");
33061 this.bodyEl.show();
33065 * Set the tooltip for the tab.
33066 * @param {String} tooltip The tab's tooltip
33068 setTooltip : function(text){
33069 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
33070 this.textEl.dom.qtip = text;
33071 this.textEl.dom.removeAttribute('title');
33073 this.textEl.dom.title = text;
33077 onTabClick : function(e){
33078 e.preventDefault();
33079 this.tabPanel.activate(this.id);
33082 onTabMouseDown : function(e){
33083 e.preventDefault();
33084 this.tabPanel.activate(this.id);
33087 getWidth : function(){
33088 return this.inner.getWidth();
33091 setWidth : function(width){
33092 var iwidth = width - this.pnode.getPadding("lr");
33093 this.inner.setWidth(iwidth);
33094 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
33095 this.pnode.setWidth(width);
33099 * Show or hide the tab
33100 * @param {Boolean} hidden True to hide or false to show.
33102 setHidden : function(hidden){
33103 this.hidden = hidden;
33104 this.pnode.setStyle("display", hidden ? "none" : "");
33108 * Returns true if this tab is "hidden"
33109 * @return {Boolean}
33111 isHidden : function(){
33112 return this.hidden;
33116 * Returns the text for this tab
33119 getText : function(){
33123 autoSize : function(){
33124 //this.el.beginMeasure();
33125 this.textEl.setWidth(1);
33127 * #2804 [new] Tabs in Roojs
33128 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
33130 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
33131 //this.el.endMeasure();
33135 * Sets the text for the tab (Note: this also sets the tooltip text)
33136 * @param {String} text The tab's text and tooltip
33138 setText : function(text){
33140 this.textEl.update(text);
33141 this.setTooltip(text);
33142 if(!this.tabPanel.resizeTabs){
33147 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
33149 activate : function(){
33150 this.tabPanel.activate(this.id);
33154 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
33156 disable : function(){
33157 if(this.tabPanel.active != this){
33158 this.disabled = true;
33159 this.pnode.addClass("disabled");
33164 * Enables this TabPanelItem if it was previously disabled.
33166 enable : function(){
33167 this.disabled = false;
33168 this.pnode.removeClass("disabled");
33172 * Sets the content for this TabPanelItem.
33173 * @param {String} content The content
33174 * @param {Boolean} loadScripts true to look for and load scripts
33176 setContent : function(content, loadScripts){
33177 this.bodyEl.update(content, loadScripts);
33181 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
33182 * @return {Roo.UpdateManager} The UpdateManager
33184 getUpdateManager : function(){
33185 return this.bodyEl.getUpdateManager();
33189 * Set a URL to be used to load the content for this TabPanelItem.
33190 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
33191 * @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)
33192 * @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)
33193 * @return {Roo.UpdateManager} The UpdateManager
33195 setUrl : function(url, params, loadOnce){
33196 if(this.refreshDelegate){
33197 this.un('activate', this.refreshDelegate);
33199 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
33200 this.on("activate", this.refreshDelegate);
33201 return this.bodyEl.getUpdateManager();
33205 _handleRefresh : function(url, params, loadOnce){
33206 if(!loadOnce || !this.loaded){
33207 var updater = this.bodyEl.getUpdateManager();
33208 updater.update(url, params, this._setLoaded.createDelegate(this));
33213 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
33214 * Will fail silently if the setUrl method has not been called.
33215 * This does not activate the panel, just updates its content.
33217 refresh : function(){
33218 if(this.refreshDelegate){
33219 this.loaded = false;
33220 this.refreshDelegate();
33225 _setLoaded : function(){
33226 this.loaded = true;
33230 closeClick : function(e){
33233 this.fireEvent("beforeclose", this, o);
33234 if(o.cancel !== true){
33235 this.tabPanel.removeTab(this.id);
33239 * The text displayed in the tooltip for the close icon.
33242 closeText : "Close this tab"
33246 Roo.TabPanel.prototype.createStrip = function(container){
33247 var strip = document.createElement("div");
33248 strip.className = "x-tabs-wrap";
33249 container.appendChild(strip);
33253 Roo.TabPanel.prototype.createStripList = function(strip){
33254 // div wrapper for retard IE
33255 // returns the "tr" element.
33256 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
33257 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
33258 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
33259 return strip.firstChild.firstChild.firstChild.firstChild;
33262 Roo.TabPanel.prototype.createBody = function(container){
33263 var body = document.createElement("div");
33264 Roo.id(body, "tab-body");
33265 Roo.fly(body).addClass("x-tabs-body");
33266 container.appendChild(body);
33270 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
33271 var body = Roo.getDom(id);
33273 body = document.createElement("div");
33276 Roo.fly(body).addClass("x-tabs-item-body");
33277 bodyEl.insertBefore(body, bodyEl.firstChild);
33281 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
33282 var td = document.createElement("td");
33283 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
33284 //stripEl.appendChild(td);
33286 td.className = "x-tabs-closable";
33287 if(!this.closeTpl){
33288 this.closeTpl = new Roo.Template(
33289 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
33290 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
33291 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
33294 var el = this.closeTpl.overwrite(td, {"text": text});
33295 var close = el.getElementsByTagName("div")[0];
33296 var inner = el.getElementsByTagName("em")[0];
33297 return {"el": el, "close": close, "inner": inner};
33300 this.tabTpl = new Roo.Template(
33301 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
33302 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
33305 var el = this.tabTpl.overwrite(td, {"text": text});
33306 var inner = el.getElementsByTagName("em")[0];
33307 return {"el": el, "inner": inner};
33311 * Ext JS Library 1.1.1
33312 * Copyright(c) 2006-2007, Ext JS, LLC.
33314 * Originally Released Under LGPL - original licence link has changed is not relivant.
33317 * <script type="text/javascript">
33321 * @class Roo.Button
33322 * @extends Roo.util.Observable
33323 * Simple Button class
33324 * @cfg {String} text The button text
33325 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
33326 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
33327 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
33328 * @cfg {Object} scope The scope of the handler
33329 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
33330 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
33331 * @cfg {Boolean} hidden True to start hidden (defaults to false)
33332 * @cfg {Boolean} disabled True to start disabled (defaults to false)
33333 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
33334 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
33335 applies if enableToggle = true)
33336 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
33337 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
33338 an {@link Roo.util.ClickRepeater} config object (defaults to false).
33340 * Create a new button
33341 * @param {Object} config The config object
33343 Roo.Button = function(renderTo, config)
33347 renderTo = config.renderTo || false;
33350 Roo.apply(this, config);
33354 * Fires when this button is clicked
33355 * @param {Button} this
33356 * @param {EventObject} e The click event
33361 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
33362 * @param {Button} this
33363 * @param {Boolean} pressed
33368 * Fires when the mouse hovers over the button
33369 * @param {Button} this
33370 * @param {Event} e The event object
33372 'mouseover' : true,
33375 * Fires when the mouse exits the button
33376 * @param {Button} this
33377 * @param {Event} e The event object
33382 * Fires when the button is rendered
33383 * @param {Button} this
33388 this.menu = Roo.menu.MenuMgr.get(this.menu);
33390 // register listeners first!! - so render can be captured..
33391 Roo.util.Observable.call(this);
33393 this.render(renderTo);
33399 Roo.extend(Roo.Button, Roo.util.Observable, {
33405 * Read-only. True if this button is hidden
33410 * Read-only. True if this button is disabled
33415 * Read-only. True if this button is pressed (only if enableToggle = true)
33421 * @cfg {Number} tabIndex
33422 * The DOM tabIndex for this button (defaults to undefined)
33424 tabIndex : undefined,
33427 * @cfg {Boolean} enableToggle
33428 * True to enable pressed/not pressed toggling (defaults to false)
33430 enableToggle: false,
33432 * @cfg {Mixed} menu
33433 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
33437 * @cfg {String} menuAlign
33438 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
33440 menuAlign : "tl-bl?",
33443 * @cfg {String} iconCls
33444 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
33446 iconCls : undefined,
33448 * @cfg {String} type
33449 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
33454 menuClassTarget: 'tr',
33457 * @cfg {String} clickEvent
33458 * The type of event to map to the button's event handler (defaults to 'click')
33460 clickEvent : 'click',
33463 * @cfg {Boolean} handleMouseEvents
33464 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
33466 handleMouseEvents : true,
33469 * @cfg {String} tooltipType
33470 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
33472 tooltipType : 'qtip',
33475 * @cfg {String} cls
33476 * A CSS class to apply to the button's main element.
33480 * @cfg {Roo.Template} template (Optional)
33481 * An {@link Roo.Template} with which to create the Button's main element. This Template must
33482 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
33483 * require code modifications if required elements (e.g. a button) aren't present.
33487 render : function(renderTo){
33489 if(this.hideParent){
33490 this.parentEl = Roo.get(renderTo);
33492 if(!this.dhconfig){
33493 if(!this.template){
33494 if(!Roo.Button.buttonTemplate){
33495 // hideous table template
33496 Roo.Button.buttonTemplate = new Roo.Template(
33497 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
33498 '<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>',
33499 "</tr></tbody></table>");
33501 this.template = Roo.Button.buttonTemplate;
33503 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
33504 var btnEl = btn.child("button:first");
33505 btnEl.on('focus', this.onFocus, this);
33506 btnEl.on('blur', this.onBlur, this);
33508 btn.addClass(this.cls);
33511 btnEl.setStyle('background-image', 'url(' +this.icon +')');
33514 btnEl.addClass(this.iconCls);
33516 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
33519 if(this.tabIndex !== undefined){
33520 btnEl.dom.tabIndex = this.tabIndex;
33523 if(typeof this.tooltip == 'object'){
33524 Roo.QuickTips.tips(Roo.apply({
33528 btnEl.dom[this.tooltipType] = this.tooltip;
33532 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
33536 this.el.dom.id = this.el.id = this.id;
33539 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
33540 this.menu.on("show", this.onMenuShow, this);
33541 this.menu.on("hide", this.onMenuHide, this);
33543 btn.addClass("x-btn");
33544 if(Roo.isIE && !Roo.isIE7){
33545 this.autoWidth.defer(1, this);
33549 if(this.handleMouseEvents){
33550 btn.on("mouseover", this.onMouseOver, this);
33551 btn.on("mouseout", this.onMouseOut, this);
33552 btn.on("mousedown", this.onMouseDown, this);
33554 btn.on(this.clickEvent, this.onClick, this);
33555 //btn.on("mouseup", this.onMouseUp, this);
33562 Roo.ButtonToggleMgr.register(this);
33564 this.el.addClass("x-btn-pressed");
33567 var repeater = new Roo.util.ClickRepeater(btn,
33568 typeof this.repeat == "object" ? this.repeat : {}
33570 repeater.on("click", this.onClick, this);
33573 this.fireEvent('render', this);
33577 * Returns the button's underlying element
33578 * @return {Roo.Element} The element
33580 getEl : function(){
33585 * Destroys this Button and removes any listeners.
33587 destroy : function(){
33588 Roo.ButtonToggleMgr.unregister(this);
33589 this.el.removeAllListeners();
33590 this.purgeListeners();
33595 autoWidth : function(){
33597 this.el.setWidth("auto");
33598 if(Roo.isIE7 && Roo.isStrict){
33599 var ib = this.el.child('button');
33600 if(ib && ib.getWidth() > 20){
33602 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
33607 this.el.beginMeasure();
33609 if(this.el.getWidth() < this.minWidth){
33610 this.el.setWidth(this.minWidth);
33613 this.el.endMeasure();
33620 * Assigns this button's click handler
33621 * @param {Function} handler The function to call when the button is clicked
33622 * @param {Object} scope (optional) Scope for the function passed in
33624 setHandler : function(handler, scope){
33625 this.handler = handler;
33626 this.scope = scope;
33630 * Sets this button's text
33631 * @param {String} text The button text
33633 setText : function(text){
33636 this.el.child("td.x-btn-center button.x-btn-text").update(text);
33642 * Gets the text for this button
33643 * @return {String} The button text
33645 getText : function(){
33653 this.hidden = false;
33655 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
33663 this.hidden = true;
33665 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
33670 * Convenience function for boolean show/hide
33671 * @param {Boolean} visible True to show, false to hide
33673 setVisible: function(visible){
33682 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
33683 * @param {Boolean} state (optional) Force a particular state
33685 toggle : function(state){
33686 state = state === undefined ? !this.pressed : state;
33687 if(state != this.pressed){
33689 this.el.addClass("x-btn-pressed");
33690 this.pressed = true;
33691 this.fireEvent("toggle", this, true);
33693 this.el.removeClass("x-btn-pressed");
33694 this.pressed = false;
33695 this.fireEvent("toggle", this, false);
33697 if(this.toggleHandler){
33698 this.toggleHandler.call(this.scope || this, this, state);
33706 focus : function(){
33707 this.el.child('button:first').focus();
33711 * Disable this button
33713 disable : function(){
33715 this.el.addClass("x-btn-disabled");
33717 this.disabled = true;
33721 * Enable this button
33723 enable : function(){
33725 this.el.removeClass("x-btn-disabled");
33727 this.disabled = false;
33731 * Convenience function for boolean enable/disable
33732 * @param {Boolean} enabled True to enable, false to disable
33734 setDisabled : function(v){
33735 this[v !== true ? "enable" : "disable"]();
33739 onClick : function(e)
33742 e.preventDefault();
33747 if(!this.disabled){
33748 if(this.enableToggle){
33751 if(this.menu && !this.menu.isVisible()){
33752 this.menu.show(this.el, this.menuAlign);
33754 this.fireEvent("click", this, e);
33756 this.el.removeClass("x-btn-over");
33757 this.handler.call(this.scope || this, this, e);
33762 onMouseOver : function(e){
33763 if(!this.disabled){
33764 this.el.addClass("x-btn-over");
33765 this.fireEvent('mouseover', this, e);
33769 onMouseOut : function(e){
33770 if(!e.within(this.el, true)){
33771 this.el.removeClass("x-btn-over");
33772 this.fireEvent('mouseout', this, e);
33776 onFocus : function(e){
33777 if(!this.disabled){
33778 this.el.addClass("x-btn-focus");
33782 onBlur : function(e){
33783 this.el.removeClass("x-btn-focus");
33786 onMouseDown : function(e){
33787 if(!this.disabled && e.button == 0){
33788 this.el.addClass("x-btn-click");
33789 Roo.get(document).on('mouseup', this.onMouseUp, this);
33793 onMouseUp : function(e){
33795 this.el.removeClass("x-btn-click");
33796 Roo.get(document).un('mouseup', this.onMouseUp, this);
33800 onMenuShow : function(e){
33801 this.el.addClass("x-btn-menu-active");
33804 onMenuHide : function(e){
33805 this.el.removeClass("x-btn-menu-active");
33809 // Private utility class used by Button
33810 Roo.ButtonToggleMgr = function(){
33813 function toggleGroup(btn, state){
33815 var g = groups[btn.toggleGroup];
33816 for(var i = 0, l = g.length; i < l; i++){
33818 g[i].toggle(false);
33825 register : function(btn){
33826 if(!btn.toggleGroup){
33829 var g = groups[btn.toggleGroup];
33831 g = groups[btn.toggleGroup] = [];
33834 btn.on("toggle", toggleGroup);
33837 unregister : function(btn){
33838 if(!btn.toggleGroup){
33841 var g = groups[btn.toggleGroup];
33844 btn.un("toggle", toggleGroup);
33850 * Ext JS Library 1.1.1
33851 * Copyright(c) 2006-2007, Ext JS, LLC.
33853 * Originally Released Under LGPL - original licence link has changed is not relivant.
33856 * <script type="text/javascript">
33860 * @class Roo.SplitButton
33861 * @extends Roo.Button
33862 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
33863 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
33864 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
33865 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
33866 * @cfg {String} arrowTooltip The title attribute of the arrow
33868 * Create a new menu button
33869 * @param {String/HTMLElement/Element} renderTo The element to append the button to
33870 * @param {Object} config The config object
33872 Roo.SplitButton = function(renderTo, config){
33873 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
33875 * @event arrowclick
33876 * Fires when this button's arrow is clicked
33877 * @param {SplitButton} this
33878 * @param {EventObject} e The click event
33880 this.addEvents({"arrowclick":true});
33883 Roo.extend(Roo.SplitButton, Roo.Button, {
33884 render : function(renderTo){
33885 // this is one sweet looking template!
33886 var tpl = new Roo.Template(
33887 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
33888 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
33889 '<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>',
33890 "</tbody></table></td><td>",
33891 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
33892 '<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>',
33893 "</tbody></table></td></tr></table>"
33895 var btn = tpl.append(renderTo, [this.text, this.type], true);
33896 var btnEl = btn.child("button");
33898 btn.addClass(this.cls);
33901 btnEl.setStyle('background-image', 'url(' +this.icon +')');
33904 btnEl.addClass(this.iconCls);
33906 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
33910 if(this.handleMouseEvents){
33911 btn.on("mouseover", this.onMouseOver, this);
33912 btn.on("mouseout", this.onMouseOut, this);
33913 btn.on("mousedown", this.onMouseDown, this);
33914 btn.on("mouseup", this.onMouseUp, this);
33916 btn.on(this.clickEvent, this.onClick, this);
33918 if(typeof this.tooltip == 'object'){
33919 Roo.QuickTips.tips(Roo.apply({
33923 btnEl.dom[this.tooltipType] = this.tooltip;
33926 if(this.arrowTooltip){
33927 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
33936 this.el.addClass("x-btn-pressed");
33938 if(Roo.isIE && !Roo.isIE7){
33939 this.autoWidth.defer(1, this);
33944 this.menu.on("show", this.onMenuShow, this);
33945 this.menu.on("hide", this.onMenuHide, this);
33947 this.fireEvent('render', this);
33951 autoWidth : function(){
33953 var tbl = this.el.child("table:first");
33954 var tbl2 = this.el.child("table:last");
33955 this.el.setWidth("auto");
33956 tbl.setWidth("auto");
33957 if(Roo.isIE7 && Roo.isStrict){
33958 var ib = this.el.child('button:first');
33959 if(ib && ib.getWidth() > 20){
33961 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
33966 this.el.beginMeasure();
33968 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
33969 tbl.setWidth(this.minWidth-tbl2.getWidth());
33972 this.el.endMeasure();
33975 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
33979 * Sets this button's click handler
33980 * @param {Function} handler The function to call when the button is clicked
33981 * @param {Object} scope (optional) Scope for the function passed above
33983 setHandler : function(handler, scope){
33984 this.handler = handler;
33985 this.scope = scope;
33989 * Sets this button's arrow click handler
33990 * @param {Function} handler The function to call when the arrow is clicked
33991 * @param {Object} scope (optional) Scope for the function passed above
33993 setArrowHandler : function(handler, scope){
33994 this.arrowHandler = handler;
33995 this.scope = scope;
34001 focus : function(){
34003 this.el.child("button:first").focus();
34008 onClick : function(e){
34009 e.preventDefault();
34010 if(!this.disabled){
34011 if(e.getTarget(".x-btn-menu-arrow-wrap")){
34012 if(this.menu && !this.menu.isVisible()){
34013 this.menu.show(this.el, this.menuAlign);
34015 this.fireEvent("arrowclick", this, e);
34016 if(this.arrowHandler){
34017 this.arrowHandler.call(this.scope || this, this, e);
34020 this.fireEvent("click", this, e);
34022 this.handler.call(this.scope || this, this, e);
34028 onMouseDown : function(e){
34029 if(!this.disabled){
34030 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
34034 onMouseUp : function(e){
34035 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
34040 // backwards compat
34041 Roo.MenuButton = Roo.SplitButton;/*
34043 * Ext JS Library 1.1.1
34044 * Copyright(c) 2006-2007, Ext JS, LLC.
34046 * Originally Released Under LGPL - original licence link has changed is not relivant.
34049 * <script type="text/javascript">
34053 * @class Roo.Toolbar
34054 * Basic Toolbar class.
34056 * Creates a new Toolbar
34057 * @param {Object} container The config object
34059 Roo.Toolbar = function(container, buttons, config)
34061 /// old consturctor format still supported..
34062 if(container instanceof Array){ // omit the container for later rendering
34063 buttons = container;
34067 if (typeof(container) == 'object' && container.xtype) {
34068 config = container;
34069 container = config.container;
34070 buttons = config.buttons || []; // not really - use items!!
34073 if (config && config.items) {
34074 xitems = config.items;
34075 delete config.items;
34077 Roo.apply(this, config);
34078 this.buttons = buttons;
34081 this.render(container);
34083 this.xitems = xitems;
34084 Roo.each(xitems, function(b) {
34090 Roo.Toolbar.prototype = {
34092 * @cfg {Array} items
34093 * array of button configs or elements to add (will be converted to a MixedCollection)
34097 * @cfg {String/HTMLElement/Element} container
34098 * The id or element that will contain the toolbar
34101 render : function(ct){
34102 this.el = Roo.get(ct);
34104 this.el.addClass(this.cls);
34106 // using a table allows for vertical alignment
34107 // 100% width is needed by Safari...
34108 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
34109 this.tr = this.el.child("tr", true);
34111 this.items = new Roo.util.MixedCollection(false, function(o){
34112 return o.id || ("item" + (++autoId));
34115 this.add.apply(this, this.buttons);
34116 delete this.buttons;
34121 * Adds element(s) to the toolbar -- this function takes a variable number of
34122 * arguments of mixed type and adds them to the toolbar.
34123 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
34125 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
34126 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
34127 * <li>Field: Any form field (equivalent to {@link #addField})</li>
34128 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
34129 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
34130 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
34131 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
34132 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
34133 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
34135 * @param {Mixed} arg2
34136 * @param {Mixed} etc.
34139 var a = arguments, l = a.length;
34140 for(var i = 0; i < l; i++){
34145 _add : function(el) {
34148 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
34151 if (el.applyTo){ // some kind of form field
34152 return this.addField(el);
34154 if (el.render){ // some kind of Toolbar.Item
34155 return this.addItem(el);
34157 if (typeof el == "string"){ // string
34158 if(el == "separator" || el == "-"){
34159 return this.addSeparator();
34162 return this.addSpacer();
34165 return this.addFill();
34167 return this.addText(el);
34170 if(el.tagName){ // element
34171 return this.addElement(el);
34173 if(typeof el == "object"){ // must be button config?
34174 return this.addButton(el);
34176 // and now what?!?!
34182 * Add an Xtype element
34183 * @param {Object} xtype Xtype Object
34184 * @return {Object} created Object
34186 addxtype : function(e){
34187 return this.add(e);
34191 * Returns the Element for this toolbar.
34192 * @return {Roo.Element}
34194 getEl : function(){
34200 * @return {Roo.Toolbar.Item} The separator item
34202 addSeparator : function(){
34203 return this.addItem(new Roo.Toolbar.Separator());
34207 * Adds a spacer element
34208 * @return {Roo.Toolbar.Spacer} The spacer item
34210 addSpacer : function(){
34211 return this.addItem(new Roo.Toolbar.Spacer());
34215 * Adds a fill element that forces subsequent additions to the right side of the toolbar
34216 * @return {Roo.Toolbar.Fill} The fill item
34218 addFill : function(){
34219 return this.addItem(new Roo.Toolbar.Fill());
34223 * Adds any standard HTML element to the toolbar
34224 * @param {String/HTMLElement/Element} el The element or id of the element to add
34225 * @return {Roo.Toolbar.Item} The element's item
34227 addElement : function(el){
34228 return this.addItem(new Roo.Toolbar.Item(el));
34231 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
34232 * @type Roo.util.MixedCollection
34237 * Adds any Toolbar.Item or subclass
34238 * @param {Roo.Toolbar.Item} item
34239 * @return {Roo.Toolbar.Item} The item
34241 addItem : function(item){
34242 var td = this.nextBlock();
34244 this.items.add(item);
34249 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
34250 * @param {Object/Array} config A button config or array of configs
34251 * @return {Roo.Toolbar.Button/Array}
34253 addButton : function(config){
34254 if(config instanceof Array){
34256 for(var i = 0, len = config.length; i < len; i++) {
34257 buttons.push(this.addButton(config[i]));
34262 if(!(config instanceof Roo.Toolbar.Button)){
34264 new Roo.Toolbar.SplitButton(config) :
34265 new Roo.Toolbar.Button(config);
34267 var td = this.nextBlock();
34274 * Adds text to the toolbar
34275 * @param {String} text The text to add
34276 * @return {Roo.Toolbar.Item} The element's item
34278 addText : function(text){
34279 return this.addItem(new Roo.Toolbar.TextItem(text));
34283 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
34284 * @param {Number} index The index where the item is to be inserted
34285 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
34286 * @return {Roo.Toolbar.Button/Item}
34288 insertButton : function(index, item){
34289 if(item instanceof Array){
34291 for(var i = 0, len = item.length; i < len; i++) {
34292 buttons.push(this.insertButton(index + i, item[i]));
34296 if (!(item instanceof Roo.Toolbar.Button)){
34297 item = new Roo.Toolbar.Button(item);
34299 var td = document.createElement("td");
34300 this.tr.insertBefore(td, this.tr.childNodes[index]);
34302 this.items.insert(index, item);
34307 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
34308 * @param {Object} config
34309 * @return {Roo.Toolbar.Item} The element's item
34311 addDom : function(config, returnEl){
34312 var td = this.nextBlock();
34313 Roo.DomHelper.overwrite(td, config);
34314 var ti = new Roo.Toolbar.Item(td.firstChild);
34316 this.items.add(ti);
34321 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
34322 * @type Roo.util.MixedCollection
34327 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
34328 * Note: the field should not have been rendered yet. For a field that has already been
34329 * rendered, use {@link #addElement}.
34330 * @param {Roo.form.Field} field
34331 * @return {Roo.ToolbarItem}
34335 addField : function(field) {
34336 if (!this.fields) {
34338 this.fields = new Roo.util.MixedCollection(false, function(o){
34339 return o.id || ("item" + (++autoId));
34344 var td = this.nextBlock();
34346 var ti = new Roo.Toolbar.Item(td.firstChild);
34348 this.items.add(ti);
34349 this.fields.add(field);
34360 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
34361 this.el.child('div').hide();
34369 this.el.child('div').show();
34373 nextBlock : function(){
34374 var td = document.createElement("td");
34375 this.tr.appendChild(td);
34380 destroy : function(){
34381 if(this.items){ // rendered?
34382 Roo.destroy.apply(Roo, this.items.items);
34384 if(this.fields){ // rendered?
34385 Roo.destroy.apply(Roo, this.fields.items);
34387 Roo.Element.uncache(this.el, this.tr);
34392 * @class Roo.Toolbar.Item
34393 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
34395 * Creates a new Item
34396 * @param {HTMLElement} el
34398 Roo.Toolbar.Item = function(el){
34400 if (typeof (el.xtype) != 'undefined') {
34405 this.el = Roo.getDom(el);
34406 this.id = Roo.id(this.el);
34407 this.hidden = false;
34412 * Fires when the button is rendered
34413 * @param {Button} this
34417 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
34419 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
34420 //Roo.Toolbar.Item.prototype = {
34423 * Get this item's HTML Element
34424 * @return {HTMLElement}
34426 getEl : function(){
34431 render : function(td){
34434 td.appendChild(this.el);
34436 this.fireEvent('render', this);
34440 * Removes and destroys this item.
34442 destroy : function(){
34443 this.td.parentNode.removeChild(this.td);
34450 this.hidden = false;
34451 this.td.style.display = "";
34458 this.hidden = true;
34459 this.td.style.display = "none";
34463 * Convenience function for boolean show/hide.
34464 * @param {Boolean} visible true to show/false to hide
34466 setVisible: function(visible){
34475 * Try to focus this item.
34477 focus : function(){
34478 Roo.fly(this.el).focus();
34482 * Disables this item.
34484 disable : function(){
34485 Roo.fly(this.td).addClass("x-item-disabled");
34486 this.disabled = true;
34487 this.el.disabled = true;
34491 * Enables this item.
34493 enable : function(){
34494 Roo.fly(this.td).removeClass("x-item-disabled");
34495 this.disabled = false;
34496 this.el.disabled = false;
34502 * @class Roo.Toolbar.Separator
34503 * @extends Roo.Toolbar.Item
34504 * A simple toolbar separator class
34506 * Creates a new Separator
34508 Roo.Toolbar.Separator = function(cfg){
34510 var s = document.createElement("span");
34511 s.className = "ytb-sep";
34516 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
34518 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
34519 enable:Roo.emptyFn,
34520 disable:Roo.emptyFn,
34525 * @class Roo.Toolbar.Spacer
34526 * @extends Roo.Toolbar.Item
34527 * A simple element that adds extra horizontal space to a toolbar.
34529 * Creates a new Spacer
34531 Roo.Toolbar.Spacer = function(cfg){
34532 var s = document.createElement("div");
34533 s.className = "ytb-spacer";
34537 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
34539 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
34540 enable:Roo.emptyFn,
34541 disable:Roo.emptyFn,
34546 * @class Roo.Toolbar.Fill
34547 * @extends Roo.Toolbar.Spacer
34548 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
34550 * Creates a new Spacer
34552 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
34554 render : function(td){
34555 td.style.width = '100%';
34556 Roo.Toolbar.Fill.superclass.render.call(this, td);
34561 * @class Roo.Toolbar.TextItem
34562 * @extends Roo.Toolbar.Item
34563 * A simple class that renders text directly into a toolbar.
34565 * Creates a new TextItem
34566 * @param {String} text
34568 Roo.Toolbar.TextItem = function(cfg){
34569 var text = cfg || "";
34570 if (typeof(cfg) == 'object') {
34571 text = cfg.text || "";
34575 var s = document.createElement("span");
34576 s.className = "ytb-text";
34577 s.innerHTML = text;
34582 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
34584 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
34587 enable:Roo.emptyFn,
34588 disable:Roo.emptyFn,
34593 * @class Roo.Toolbar.Button
34594 * @extends Roo.Button
34595 * A button that renders into a toolbar.
34597 * Creates a new Button
34598 * @param {Object} config A standard {@link Roo.Button} config object
34600 Roo.Toolbar.Button = function(config){
34601 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
34603 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
34604 render : function(td){
34606 Roo.Toolbar.Button.superclass.render.call(this, td);
34610 * Removes and destroys this button
34612 destroy : function(){
34613 Roo.Toolbar.Button.superclass.destroy.call(this);
34614 this.td.parentNode.removeChild(this.td);
34618 * Shows this button
34621 this.hidden = false;
34622 this.td.style.display = "";
34626 * Hides this button
34629 this.hidden = true;
34630 this.td.style.display = "none";
34634 * Disables this item
34636 disable : function(){
34637 Roo.fly(this.td).addClass("x-item-disabled");
34638 this.disabled = true;
34642 * Enables this item
34644 enable : function(){
34645 Roo.fly(this.td).removeClass("x-item-disabled");
34646 this.disabled = false;
34649 // backwards compat
34650 Roo.ToolbarButton = Roo.Toolbar.Button;
34653 * @class Roo.Toolbar.SplitButton
34654 * @extends Roo.SplitButton
34655 * A menu button that renders into a toolbar.
34657 * Creates a new SplitButton
34658 * @param {Object} config A standard {@link Roo.SplitButton} config object
34660 Roo.Toolbar.SplitButton = function(config){
34661 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
34663 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
34664 render : function(td){
34666 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
34670 * Removes and destroys this button
34672 destroy : function(){
34673 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
34674 this.td.parentNode.removeChild(this.td);
34678 * Shows this button
34681 this.hidden = false;
34682 this.td.style.display = "";
34686 * Hides this button
34689 this.hidden = true;
34690 this.td.style.display = "none";
34694 // backwards compat
34695 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
34697 * Ext JS Library 1.1.1
34698 * Copyright(c) 2006-2007, Ext JS, LLC.
34700 * Originally Released Under LGPL - original licence link has changed is not relivant.
34703 * <script type="text/javascript">
34707 * @class Roo.PagingToolbar
34708 * @extends Roo.Toolbar
34709 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
34711 * Create a new PagingToolbar
34712 * @param {Object} config The config object
34714 Roo.PagingToolbar = function(el, ds, config)
34716 // old args format still supported... - xtype is prefered..
34717 if (typeof(el) == 'object' && el.xtype) {
34718 // created from xtype...
34720 ds = el.dataSource;
34721 el = config.container;
34724 if (config.items) {
34725 items = config.items;
34729 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
34732 this.renderButtons(this.el);
34735 // supprot items array.
34737 Roo.each(items, function(e) {
34738 this.add(Roo.factory(e));
34743 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
34745 * @cfg {Roo.data.Store} dataSource
34746 * The underlying data store providing the paged data
34749 * @cfg {String/HTMLElement/Element} container
34750 * container The id or element that will contain the toolbar
34753 * @cfg {Boolean} displayInfo
34754 * True to display the displayMsg (defaults to false)
34757 * @cfg {Number} pageSize
34758 * The number of records to display per page (defaults to 20)
34762 * @cfg {String} displayMsg
34763 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
34765 displayMsg : 'Displaying {0} - {1} of {2}',
34767 * @cfg {String} emptyMsg
34768 * The message to display when no records are found (defaults to "No data to display")
34770 emptyMsg : 'No data to display',
34772 * Customizable piece of the default paging text (defaults to "Page")
34775 beforePageText : "Page",
34777 * Customizable piece of the default paging text (defaults to "of %0")
34780 afterPageText : "of {0}",
34782 * Customizable piece of the default paging text (defaults to "First Page")
34785 firstText : "First Page",
34787 * Customizable piece of the default paging text (defaults to "Previous Page")
34790 prevText : "Previous Page",
34792 * Customizable piece of the default paging text (defaults to "Next Page")
34795 nextText : "Next Page",
34797 * Customizable piece of the default paging text (defaults to "Last Page")
34800 lastText : "Last Page",
34802 * Customizable piece of the default paging text (defaults to "Refresh")
34805 refreshText : "Refresh",
34808 renderButtons : function(el){
34809 Roo.PagingToolbar.superclass.render.call(this, el);
34810 this.first = this.addButton({
34811 tooltip: this.firstText,
34812 cls: "x-btn-icon x-grid-page-first",
34814 handler: this.onClick.createDelegate(this, ["first"])
34816 this.prev = this.addButton({
34817 tooltip: this.prevText,
34818 cls: "x-btn-icon x-grid-page-prev",
34820 handler: this.onClick.createDelegate(this, ["prev"])
34822 //this.addSeparator();
34823 this.add(this.beforePageText);
34824 this.field = Roo.get(this.addDom({
34829 cls: "x-grid-page-number"
34831 this.field.on("keydown", this.onPagingKeydown, this);
34832 this.field.on("focus", function(){this.dom.select();});
34833 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
34834 this.field.setHeight(18);
34835 //this.addSeparator();
34836 this.next = this.addButton({
34837 tooltip: this.nextText,
34838 cls: "x-btn-icon x-grid-page-next",
34840 handler: this.onClick.createDelegate(this, ["next"])
34842 this.last = this.addButton({
34843 tooltip: this.lastText,
34844 cls: "x-btn-icon x-grid-page-last",
34846 handler: this.onClick.createDelegate(this, ["last"])
34848 //this.addSeparator();
34849 this.loading = this.addButton({
34850 tooltip: this.refreshText,
34851 cls: "x-btn-icon x-grid-loading",
34852 handler: this.onClick.createDelegate(this, ["refresh"])
34855 if(this.displayInfo){
34856 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
34861 updateInfo : function(){
34862 if(this.displayEl){
34863 var count = this.ds.getCount();
34864 var msg = count == 0 ?
34868 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
34870 this.displayEl.update(msg);
34875 onLoad : function(ds, r, o){
34876 this.cursor = o.params ? o.params.start : 0;
34877 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
34879 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
34880 this.field.dom.value = ap;
34881 this.first.setDisabled(ap == 1);
34882 this.prev.setDisabled(ap == 1);
34883 this.next.setDisabled(ap == ps);
34884 this.last.setDisabled(ap == ps);
34885 this.loading.enable();
34890 getPageData : function(){
34891 var total = this.ds.getTotalCount();
34894 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
34895 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
34900 onLoadError : function(){
34901 this.loading.enable();
34905 onPagingKeydown : function(e){
34906 var k = e.getKey();
34907 var d = this.getPageData();
34909 var v = this.field.dom.value, pageNum;
34910 if(!v || isNaN(pageNum = parseInt(v, 10))){
34911 this.field.dom.value = d.activePage;
34914 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
34915 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
34918 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))
34920 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
34921 this.field.dom.value = pageNum;
34922 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
34925 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
34927 var v = this.field.dom.value, pageNum;
34928 var increment = (e.shiftKey) ? 10 : 1;
34929 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
34932 if(!v || isNaN(pageNum = parseInt(v, 10))) {
34933 this.field.dom.value = d.activePage;
34936 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
34938 this.field.dom.value = parseInt(v, 10) + increment;
34939 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
34940 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
34947 beforeLoad : function(){
34949 this.loading.disable();
34954 onClick : function(which){
34958 ds.load({params:{start: 0, limit: this.pageSize}});
34961 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
34964 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
34967 var total = ds.getTotalCount();
34968 var extra = total % this.pageSize;
34969 var lastStart = extra ? (total - extra) : total-this.pageSize;
34970 ds.load({params:{start: lastStart, limit: this.pageSize}});
34973 ds.load({params:{start: this.cursor, limit: this.pageSize}});
34979 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
34980 * @param {Roo.data.Store} store The data store to unbind
34982 unbind : function(ds){
34983 ds.un("beforeload", this.beforeLoad, this);
34984 ds.un("load", this.onLoad, this);
34985 ds.un("loadexception", this.onLoadError, this);
34986 ds.un("remove", this.updateInfo, this);
34987 ds.un("add", this.updateInfo, this);
34988 this.ds = undefined;
34992 * Binds the paging toolbar to the specified {@link Roo.data.Store}
34993 * @param {Roo.data.Store} store The data store to bind
34995 bind : function(ds){
34996 ds.on("beforeload", this.beforeLoad, this);
34997 ds.on("load", this.onLoad, this);
34998 ds.on("loadexception", this.onLoadError, this);
34999 ds.on("remove", this.updateInfo, this);
35000 ds.on("add", this.updateInfo, this);
35005 * Ext JS Library 1.1.1
35006 * Copyright(c) 2006-2007, Ext JS, LLC.
35008 * Originally Released Under LGPL - original licence link has changed is not relivant.
35011 * <script type="text/javascript">
35015 * @class Roo.Resizable
35016 * @extends Roo.util.Observable
35017 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
35018 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
35019 * 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
35020 * the element will be wrapped for you automatically.</p>
35021 * <p>Here is the list of valid resize handles:</p>
35024 ------ -------------------
35033 'hd' horizontal drag
35036 * <p>Here's an example showing the creation of a typical Resizable:</p>
35038 var resizer = new Roo.Resizable("element-id", {
35046 resizer.on("resize", myHandler);
35048 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
35049 * resizer.east.setDisplayed(false);</p>
35050 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
35051 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
35052 * resize operation's new size (defaults to [0, 0])
35053 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
35054 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
35055 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
35056 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
35057 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
35058 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
35059 * @cfg {Number} width The width of the element in pixels (defaults to null)
35060 * @cfg {Number} height The height of the element in pixels (defaults to null)
35061 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
35062 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
35063 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
35064 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
35065 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
35066 * in favor of the handles config option (defaults to false)
35067 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
35068 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
35069 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
35070 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
35071 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
35072 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
35073 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
35074 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
35075 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
35076 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
35077 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
35079 * Create a new resizable component
35080 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
35081 * @param {Object} config configuration options
35083 Roo.Resizable = function(el, config)
35085 this.el = Roo.get(el);
35087 if(config && config.wrap){
35088 config.resizeChild = this.el;
35089 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
35090 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
35091 this.el.setStyle("overflow", "hidden");
35092 this.el.setPositioning(config.resizeChild.getPositioning());
35093 config.resizeChild.clearPositioning();
35094 if(!config.width || !config.height){
35095 var csize = config.resizeChild.getSize();
35096 this.el.setSize(csize.width, csize.height);
35098 if(config.pinned && !config.adjustments){
35099 config.adjustments = "auto";
35103 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
35104 this.proxy.unselectable();
35105 this.proxy.enableDisplayMode('block');
35107 Roo.apply(this, config);
35110 this.disableTrackOver = true;
35111 this.el.addClass("x-resizable-pinned");
35113 // if the element isn't positioned, make it relative
35114 var position = this.el.getStyle("position");
35115 if(position != "absolute" && position != "fixed"){
35116 this.el.setStyle("position", "relative");
35118 if(!this.handles){ // no handles passed, must be legacy style
35119 this.handles = 's,e,se';
35120 if(this.multiDirectional){
35121 this.handles += ',n,w';
35124 if(this.handles == "all"){
35125 this.handles = "n s e w ne nw se sw";
35127 var hs = this.handles.split(/\s*?[,;]\s*?| /);
35128 var ps = Roo.Resizable.positions;
35129 for(var i = 0, len = hs.length; i < len; i++){
35130 if(hs[i] && ps[hs[i]]){
35131 var pos = ps[hs[i]];
35132 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
35136 this.corner = this.southeast;
35138 // updateBox = the box can move..
35139 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
35140 this.updateBox = true;
35143 this.activeHandle = null;
35145 if(this.resizeChild){
35146 if(typeof this.resizeChild == "boolean"){
35147 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
35149 this.resizeChild = Roo.get(this.resizeChild, true);
35153 if(this.adjustments == "auto"){
35154 var rc = this.resizeChild;
35155 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
35156 if(rc && (hw || hn)){
35157 rc.position("relative");
35158 rc.setLeft(hw ? hw.el.getWidth() : 0);
35159 rc.setTop(hn ? hn.el.getHeight() : 0);
35161 this.adjustments = [
35162 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
35163 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
35167 if(this.draggable){
35168 this.dd = this.dynamic ?
35169 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
35170 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
35176 * @event beforeresize
35177 * Fired before resize is allowed. Set enabled to false to cancel resize.
35178 * @param {Roo.Resizable} this
35179 * @param {Roo.EventObject} e The mousedown event
35181 "beforeresize" : true,
35184 * Fired a resizing.
35185 * @param {Roo.Resizable} this
35186 * @param {Number} x The new x position
35187 * @param {Number} y The new y position
35188 * @param {Number} w The new w width
35189 * @param {Number} h The new h hight
35190 * @param {Roo.EventObject} e The mouseup event
35195 * Fired after a resize.
35196 * @param {Roo.Resizable} this
35197 * @param {Number} width The new width
35198 * @param {Number} height The new height
35199 * @param {Roo.EventObject} e The mouseup event
35204 if(this.width !== null && this.height !== null){
35205 this.resizeTo(this.width, this.height);
35207 this.updateChildSize();
35210 this.el.dom.style.zoom = 1;
35212 Roo.Resizable.superclass.constructor.call(this);
35215 Roo.extend(Roo.Resizable, Roo.util.Observable, {
35216 resizeChild : false,
35217 adjustments : [0, 0],
35227 multiDirectional : false,
35228 disableTrackOver : false,
35229 easing : 'easeOutStrong',
35230 widthIncrement : 0,
35231 heightIncrement : 0,
35235 preserveRatio : false,
35236 transparent: false,
35242 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
35244 constrainTo: undefined,
35246 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
35248 resizeRegion: undefined,
35252 * Perform a manual resize
35253 * @param {Number} width
35254 * @param {Number} height
35256 resizeTo : function(width, height){
35257 this.el.setSize(width, height);
35258 this.updateChildSize();
35259 this.fireEvent("resize", this, width, height, null);
35263 startSizing : function(e, handle){
35264 this.fireEvent("beforeresize", this, e);
35265 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
35268 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
35269 this.overlay.unselectable();
35270 this.overlay.enableDisplayMode("block");
35271 this.overlay.on("mousemove", this.onMouseMove, this);
35272 this.overlay.on("mouseup", this.onMouseUp, this);
35274 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
35276 this.resizing = true;
35277 this.startBox = this.el.getBox();
35278 this.startPoint = e.getXY();
35279 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
35280 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
35282 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
35283 this.overlay.show();
35285 if(this.constrainTo) {
35286 var ct = Roo.get(this.constrainTo);
35287 this.resizeRegion = ct.getRegion().adjust(
35288 ct.getFrameWidth('t'),
35289 ct.getFrameWidth('l'),
35290 -ct.getFrameWidth('b'),
35291 -ct.getFrameWidth('r')
35295 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
35297 this.proxy.setBox(this.startBox);
35299 this.proxy.setStyle('visibility', 'visible');
35305 onMouseDown : function(handle, e){
35308 this.activeHandle = handle;
35309 this.startSizing(e, handle);
35314 onMouseUp : function(e){
35315 var size = this.resizeElement();
35316 this.resizing = false;
35318 this.overlay.hide();
35320 this.fireEvent("resize", this, size.width, size.height, e);
35324 updateChildSize : function(){
35326 if(this.resizeChild){
35328 var child = this.resizeChild;
35329 var adj = this.adjustments;
35330 if(el.dom.offsetWidth){
35331 var b = el.getSize(true);
35332 child.setSize(b.width+adj[0], b.height+adj[1]);
35334 // Second call here for IE
35335 // The first call enables instant resizing and
35336 // the second call corrects scroll bars if they
35339 setTimeout(function(){
35340 if(el.dom.offsetWidth){
35341 var b = el.getSize(true);
35342 child.setSize(b.width+adj[0], b.height+adj[1]);
35350 snap : function(value, inc, min){
35351 if(!inc || !value) {
35354 var newValue = value;
35355 var m = value % inc;
35358 newValue = value + (inc-m);
35360 newValue = value - m;
35363 return Math.max(min, newValue);
35367 resizeElement : function(){
35368 var box = this.proxy.getBox();
35369 if(this.updateBox){
35370 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
35372 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
35374 this.updateChildSize();
35382 constrain : function(v, diff, m, mx){
35385 }else if(v - diff > mx){
35392 onMouseMove : function(e){
35395 try{// try catch so if something goes wrong the user doesn't get hung
35397 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
35401 //var curXY = this.startPoint;
35402 var curSize = this.curSize || this.startBox;
35403 var x = this.startBox.x, y = this.startBox.y;
35404 var ox = x, oy = y;
35405 var w = curSize.width, h = curSize.height;
35406 var ow = w, oh = h;
35407 var mw = this.minWidth, mh = this.minHeight;
35408 var mxw = this.maxWidth, mxh = this.maxHeight;
35409 var wi = this.widthIncrement;
35410 var hi = this.heightIncrement;
35412 var eventXY = e.getXY();
35413 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
35414 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
35416 var pos = this.activeHandle.position;
35421 w = Math.min(Math.max(mw, w), mxw);
35426 h = Math.min(Math.max(mh, h), mxh);
35431 w = Math.min(Math.max(mw, w), mxw);
35432 h = Math.min(Math.max(mh, h), mxh);
35435 diffY = this.constrain(h, diffY, mh, mxh);
35442 var adiffX = Math.abs(diffX);
35443 var sub = (adiffX % wi); // how much
35444 if (sub > (wi/2)) { // far enough to snap
35445 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
35447 // remove difference..
35448 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
35452 x = Math.max(this.minX, x);
35455 diffX = this.constrain(w, diffX, mw, mxw);
35461 w = Math.min(Math.max(mw, w), mxw);
35462 diffY = this.constrain(h, diffY, mh, mxh);
35467 diffX = this.constrain(w, diffX, mw, mxw);
35468 diffY = this.constrain(h, diffY, mh, mxh);
35475 diffX = this.constrain(w, diffX, mw, mxw);
35477 h = Math.min(Math.max(mh, h), mxh);
35483 var sw = this.snap(w, wi, mw);
35484 var sh = this.snap(h, hi, mh);
35485 if(sw != w || sh != h){
35508 if(this.preserveRatio){
35513 h = Math.min(Math.max(mh, h), mxh);
35518 w = Math.min(Math.max(mw, w), mxw);
35523 w = Math.min(Math.max(mw, w), mxw);
35529 w = Math.min(Math.max(mw, w), mxw);
35535 h = Math.min(Math.max(mh, h), mxh);
35543 h = Math.min(Math.max(mh, h), mxh);
35553 h = Math.min(Math.max(mh, h), mxh);
35561 if (pos == 'hdrag') {
35564 this.proxy.setBounds(x, y, w, h);
35566 this.resizeElement();
35570 this.fireEvent("resizing", this, x, y, w, h, e);
35574 handleOver : function(){
35576 this.el.addClass("x-resizable-over");
35581 handleOut : function(){
35582 if(!this.resizing){
35583 this.el.removeClass("x-resizable-over");
35588 * Returns the element this component is bound to.
35589 * @return {Roo.Element}
35591 getEl : function(){
35596 * Returns the resizeChild element (or null).
35597 * @return {Roo.Element}
35599 getResizeChild : function(){
35600 return this.resizeChild;
35602 groupHandler : function()
35607 * Destroys this resizable. If the element was wrapped and
35608 * removeEl is not true then the element remains.
35609 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
35611 destroy : function(removeEl){
35612 this.proxy.remove();
35614 this.overlay.removeAllListeners();
35615 this.overlay.remove();
35617 var ps = Roo.Resizable.positions;
35619 if(typeof ps[k] != "function" && this[ps[k]]){
35620 var h = this[ps[k]];
35621 h.el.removeAllListeners();
35626 this.el.update("");
35633 // hash to map config positions to true positions
35634 Roo.Resizable.positions = {
35635 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
35640 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
35642 // only initialize the template if resizable is used
35643 var tpl = Roo.DomHelper.createTemplate(
35644 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
35647 Roo.Resizable.Handle.prototype.tpl = tpl;
35649 this.position = pos;
35651 // show north drag fro topdra
35652 var handlepos = pos == 'hdrag' ? 'north' : pos;
35654 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
35655 if (pos == 'hdrag') {
35656 this.el.setStyle('cursor', 'pointer');
35658 this.el.unselectable();
35660 this.el.setOpacity(0);
35662 this.el.on("mousedown", this.onMouseDown, this);
35663 if(!disableTrackOver){
35664 this.el.on("mouseover", this.onMouseOver, this);
35665 this.el.on("mouseout", this.onMouseOut, this);
35670 Roo.Resizable.Handle.prototype = {
35671 afterResize : function(rz){
35676 onMouseDown : function(e){
35677 this.rz.onMouseDown(this, e);
35680 onMouseOver : function(e){
35681 this.rz.handleOver(this, e);
35684 onMouseOut : function(e){
35685 this.rz.handleOut(this, e);
35689 * Ext JS Library 1.1.1
35690 * Copyright(c) 2006-2007, Ext JS, LLC.
35692 * Originally Released Under LGPL - original licence link has changed is not relivant.
35695 * <script type="text/javascript">
35699 * @class Roo.Editor
35700 * @extends Roo.Component
35701 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
35703 * Create a new Editor
35704 * @param {Roo.form.Field} field The Field object (or descendant)
35705 * @param {Object} config The config object
35707 Roo.Editor = function(field, config){
35708 Roo.Editor.superclass.constructor.call(this, config);
35709 this.field = field;
35712 * @event beforestartedit
35713 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35714 * false from the handler of this event.
35715 * @param {Editor} this
35716 * @param {Roo.Element} boundEl The underlying element bound to this editor
35717 * @param {Mixed} value The field value being set
35719 "beforestartedit" : true,
35722 * Fires when this editor is displayed
35723 * @param {Roo.Element} boundEl The underlying element bound to this editor
35724 * @param {Mixed} value The starting field value
35726 "startedit" : true,
35728 * @event beforecomplete
35729 * Fires after a change has been made to the field, but before the change is reflected in the underlying
35730 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
35731 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
35732 * event will not fire since no edit actually occurred.
35733 * @param {Editor} this
35734 * @param {Mixed} value The current field value
35735 * @param {Mixed} startValue The original field value
35737 "beforecomplete" : true,
35740 * Fires after editing is complete and any changed value has been written to the underlying field.
35741 * @param {Editor} this
35742 * @param {Mixed} value The current field value
35743 * @param {Mixed} startValue The original field value
35747 * @event specialkey
35748 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35749 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35750 * @param {Roo.form.Field} this
35751 * @param {Roo.EventObject} e The event object
35753 "specialkey" : true
35757 Roo.extend(Roo.Editor, Roo.Component, {
35759 * @cfg {Boolean/String} autosize
35760 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
35761 * or "height" to adopt the height only (defaults to false)
35764 * @cfg {Boolean} revertInvalid
35765 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
35766 * validation fails (defaults to true)
35769 * @cfg {Boolean} ignoreNoChange
35770 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
35771 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
35772 * will never be ignored.
35775 * @cfg {Boolean} hideEl
35776 * False to keep the bound element visible while the editor is displayed (defaults to true)
35779 * @cfg {Mixed} value
35780 * The data value of the underlying field (defaults to "")
35784 * @cfg {String} alignment
35785 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
35789 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
35790 * for bottom-right shadow (defaults to "frame")
35794 * @cfg {Boolean} constrain True to constrain the editor to the viewport
35798 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
35800 completeOnEnter : false,
35802 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
35804 cancelOnEsc : false,
35806 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
35811 onRender : function(ct, position){
35812 this.el = new Roo.Layer({
35813 shadow: this.shadow,
35819 constrain: this.constrain
35821 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
35822 if(this.field.msgTarget != 'title'){
35823 this.field.msgTarget = 'qtip';
35825 this.field.render(this.el);
35827 this.field.el.dom.setAttribute('autocomplete', 'off');
35829 this.field.on("specialkey", this.onSpecialKey, this);
35830 if(this.swallowKeys){
35831 this.field.el.swallowEvent(['keydown','keypress']);
35834 this.field.on("blur", this.onBlur, this);
35835 if(this.field.grow){
35836 this.field.on("autosize", this.el.sync, this.el, {delay:1});
35840 onSpecialKey : function(field, e)
35842 //Roo.log('editor onSpecialKey');
35843 if(this.completeOnEnter && e.getKey() == e.ENTER){
35845 this.completeEdit();
35848 // do not fire special key otherwise it might hide close the editor...
35849 if(e.getKey() == e.ENTER){
35852 if(this.cancelOnEsc && e.getKey() == e.ESC){
35856 this.fireEvent('specialkey', field, e);
35861 * Starts the editing process and shows the editor.
35862 * @param {String/HTMLElement/Element} el The element to edit
35863 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
35864 * to the innerHTML of el.
35866 startEdit : function(el, value){
35868 this.completeEdit();
35870 this.boundEl = Roo.get(el);
35871 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
35872 if(!this.rendered){
35873 this.render(this.parentEl || document.body);
35875 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
35878 this.startValue = v;
35879 this.field.setValue(v);
35881 var sz = this.boundEl.getSize();
35882 switch(this.autoSize){
35884 this.setSize(sz.width, "");
35887 this.setSize("", sz.height);
35890 this.setSize(sz.width, sz.height);
35893 this.el.alignTo(this.boundEl, this.alignment);
35894 this.editing = true;
35896 Roo.QuickTips.disable();
35902 * Sets the height and width of this editor.
35903 * @param {Number} width The new width
35904 * @param {Number} height The new height
35906 setSize : function(w, h){
35907 this.field.setSize(w, h);
35914 * Realigns the editor to the bound field based on the current alignment config value.
35916 realign : function(){
35917 this.el.alignTo(this.boundEl, this.alignment);
35921 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
35922 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
35924 completeEdit : function(remainVisible){
35928 var v = this.getValue();
35929 if(this.revertInvalid !== false && !this.field.isValid()){
35930 v = this.startValue;
35931 this.cancelEdit(true);
35933 if(String(v) === String(this.startValue) && this.ignoreNoChange){
35934 this.editing = false;
35938 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
35939 this.editing = false;
35940 if(this.updateEl && this.boundEl){
35941 this.boundEl.update(v);
35943 if(remainVisible !== true){
35946 this.fireEvent("complete", this, v, this.startValue);
35951 onShow : function(){
35953 if(this.hideEl !== false){
35954 this.boundEl.hide();
35957 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
35958 this.fixIEFocus = true;
35959 this.deferredFocus.defer(50, this);
35961 this.field.focus();
35963 this.fireEvent("startedit", this.boundEl, this.startValue);
35966 deferredFocus : function(){
35968 this.field.focus();
35973 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
35974 * reverted to the original starting value.
35975 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
35976 * cancel (defaults to false)
35978 cancelEdit : function(remainVisible){
35980 this.setValue(this.startValue);
35981 if(remainVisible !== true){
35988 onBlur : function(){
35989 if(this.allowBlur !== true && this.editing){
35990 this.completeEdit();
35995 onHide : function(){
35997 this.completeEdit();
36001 if(this.field.collapse){
36002 this.field.collapse();
36005 if(this.hideEl !== false){
36006 this.boundEl.show();
36009 Roo.QuickTips.enable();
36014 * Sets the data value of the editor
36015 * @param {Mixed} value Any valid value supported by the underlying field
36017 setValue : function(v){
36018 this.field.setValue(v);
36022 * Gets the data value of the editor
36023 * @return {Mixed} The data value
36025 getValue : function(){
36026 return this.field.getValue();
36030 * Ext JS Library 1.1.1
36031 * Copyright(c) 2006-2007, Ext JS, LLC.
36033 * Originally Released Under LGPL - original licence link has changed is not relivant.
36036 * <script type="text/javascript">
36040 * @class Roo.BasicDialog
36041 * @extends Roo.util.Observable
36042 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
36044 var dlg = new Roo.BasicDialog("my-dlg", {
36053 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
36054 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
36055 dlg.addButton('Cancel', dlg.hide, dlg);
36058 <b>A Dialog should always be a direct child of the body element.</b>
36059 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
36060 * @cfg {String} title Default text to display in the title bar (defaults to null)
36061 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
36062 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
36063 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
36064 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
36065 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
36066 * (defaults to null with no animation)
36067 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
36068 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
36069 * property for valid values (defaults to 'all')
36070 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
36071 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
36072 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
36073 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
36074 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
36075 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
36076 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
36077 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
36078 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
36079 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
36080 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
36081 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
36082 * draggable = true (defaults to false)
36083 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
36084 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
36085 * shadow (defaults to false)
36086 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
36087 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
36088 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
36089 * @cfg {Array} buttons Array of buttons
36090 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
36092 * Create a new BasicDialog.
36093 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
36094 * @param {Object} config Configuration options
36096 Roo.BasicDialog = function(el, config){
36097 this.el = Roo.get(el);
36098 var dh = Roo.DomHelper;
36099 if(!this.el && config && config.autoCreate){
36100 if(typeof config.autoCreate == "object"){
36101 if(!config.autoCreate.id){
36102 config.autoCreate.id = el;
36104 this.el = dh.append(document.body,
36105 config.autoCreate, true);
36107 this.el = dh.append(document.body,
36108 {tag: "div", id: el, style:'visibility:hidden;'}, true);
36112 el.setDisplayed(true);
36113 el.hide = this.hideAction;
36115 el.addClass("x-dlg");
36117 Roo.apply(this, config);
36119 this.proxy = el.createProxy("x-dlg-proxy");
36120 this.proxy.hide = this.hideAction;
36121 this.proxy.setOpacity(.5);
36125 el.setWidth(config.width);
36128 el.setHeight(config.height);
36130 this.size = el.getSize();
36131 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
36132 this.xy = [config.x,config.y];
36134 this.xy = el.getCenterXY(true);
36136 /** The header element @type Roo.Element */
36137 this.header = el.child("> .x-dlg-hd");
36138 /** The body element @type Roo.Element */
36139 this.body = el.child("> .x-dlg-bd");
36140 /** The footer element @type Roo.Element */
36141 this.footer = el.child("> .x-dlg-ft");
36144 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
36147 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
36150 this.header.unselectable();
36152 this.header.update(this.title);
36154 // this element allows the dialog to be focused for keyboard event
36155 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
36156 this.focusEl.swallowEvent("click", true);
36158 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
36160 // wrap the body and footer for special rendering
36161 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
36163 this.bwrap.dom.appendChild(this.footer.dom);
36166 this.bg = this.el.createChild({
36167 tag: "div", cls:"x-dlg-bg",
36168 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
36170 this.centerBg = this.bg.child("div.x-dlg-bg-center");
36173 if(this.autoScroll !== false && !this.autoTabs){
36174 this.body.setStyle("overflow", "auto");
36177 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
36179 if(this.closable !== false){
36180 this.el.addClass("x-dlg-closable");
36181 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
36182 this.close.on("click", this.closeClick, this);
36183 this.close.addClassOnOver("x-dlg-close-over");
36185 if(this.collapsible !== false){
36186 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
36187 this.collapseBtn.on("click", this.collapseClick, this);
36188 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
36189 this.header.on("dblclick", this.collapseClick, this);
36191 if(this.resizable !== false){
36192 this.el.addClass("x-dlg-resizable");
36193 this.resizer = new Roo.Resizable(el, {
36194 minWidth: this.minWidth || 80,
36195 minHeight:this.minHeight || 80,
36196 handles: this.resizeHandles || "all",
36199 this.resizer.on("beforeresize", this.beforeResize, this);
36200 this.resizer.on("resize", this.onResize, this);
36202 if(this.draggable !== false){
36203 el.addClass("x-dlg-draggable");
36204 if (!this.proxyDrag) {
36205 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
36208 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
36210 dd.setHandleElId(this.header.id);
36211 dd.endDrag = this.endMove.createDelegate(this);
36212 dd.startDrag = this.startMove.createDelegate(this);
36213 dd.onDrag = this.onDrag.createDelegate(this);
36218 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
36219 this.mask.enableDisplayMode("block");
36221 this.el.addClass("x-dlg-modal");
36224 this.shadow = new Roo.Shadow({
36225 mode : typeof this.shadow == "string" ? this.shadow : "sides",
36226 offset : this.shadowOffset
36229 this.shadowOffset = 0;
36231 if(Roo.useShims && this.shim !== false){
36232 this.shim = this.el.createShim();
36233 this.shim.hide = this.hideAction;
36241 if (this.buttons) {
36242 var bts= this.buttons;
36244 Roo.each(bts, function(b) {
36253 * Fires when a key is pressed
36254 * @param {Roo.BasicDialog} this
36255 * @param {Roo.EventObject} e
36260 * Fires when this dialog is moved by the user.
36261 * @param {Roo.BasicDialog} this
36262 * @param {Number} x The new page X
36263 * @param {Number} y The new page Y
36268 * Fires when this dialog is resized by the user.
36269 * @param {Roo.BasicDialog} this
36270 * @param {Number} width The new width
36271 * @param {Number} height The new height
36275 * @event beforehide
36276 * Fires before this dialog is hidden.
36277 * @param {Roo.BasicDialog} this
36279 "beforehide" : true,
36282 * Fires when this dialog is hidden.
36283 * @param {Roo.BasicDialog} this
36287 * @event beforeshow
36288 * Fires before this dialog is shown.
36289 * @param {Roo.BasicDialog} this
36291 "beforeshow" : true,
36294 * Fires when this dialog is shown.
36295 * @param {Roo.BasicDialog} this
36299 el.on("keydown", this.onKeyDown, this);
36300 el.on("mousedown", this.toFront, this);
36301 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
36303 Roo.DialogManager.register(this);
36304 Roo.BasicDialog.superclass.constructor.call(this);
36307 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
36308 shadowOffset: Roo.isIE ? 6 : 5,
36311 minButtonWidth: 75,
36312 defaultButton: null,
36313 buttonAlign: "right",
36318 * Sets the dialog title text
36319 * @param {String} text The title text to display
36320 * @return {Roo.BasicDialog} this
36322 setTitle : function(text){
36323 this.header.update(text);
36328 closeClick : function(){
36333 collapseClick : function(){
36334 this[this.collapsed ? "expand" : "collapse"]();
36338 * Collapses the dialog to its minimized state (only the title bar is visible).
36339 * Equivalent to the user clicking the collapse dialog button.
36341 collapse : function(){
36342 if(!this.collapsed){
36343 this.collapsed = true;
36344 this.el.addClass("x-dlg-collapsed");
36345 this.restoreHeight = this.el.getHeight();
36346 this.resizeTo(this.el.getWidth(), this.header.getHeight());
36351 * Expands a collapsed dialog back to its normal state. Equivalent to the user
36352 * clicking the expand dialog button.
36354 expand : function(){
36355 if(this.collapsed){
36356 this.collapsed = false;
36357 this.el.removeClass("x-dlg-collapsed");
36358 this.resizeTo(this.el.getWidth(), this.restoreHeight);
36363 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
36364 * @return {Roo.TabPanel} The tabs component
36366 initTabs : function(){
36367 var tabs = this.getTabs();
36368 while(tabs.getTab(0)){
36371 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
36373 tabs.addTab(Roo.id(dom), dom.title);
36381 beforeResize : function(){
36382 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
36386 onResize : function(){
36387 this.refreshSize();
36388 this.syncBodyHeight();
36389 this.adjustAssets();
36391 this.fireEvent("resize", this, this.size.width, this.size.height);
36395 onKeyDown : function(e){
36396 if(this.isVisible()){
36397 this.fireEvent("keydown", this, e);
36402 * Resizes the dialog.
36403 * @param {Number} width
36404 * @param {Number} height
36405 * @return {Roo.BasicDialog} this
36407 resizeTo : function(width, height){
36408 this.el.setSize(width, height);
36409 this.size = {width: width, height: height};
36410 this.syncBodyHeight();
36411 if(this.fixedcenter){
36414 if(this.isVisible()){
36415 this.constrainXY();
36416 this.adjustAssets();
36418 this.fireEvent("resize", this, width, height);
36424 * Resizes the dialog to fit the specified content size.
36425 * @param {Number} width
36426 * @param {Number} height
36427 * @return {Roo.BasicDialog} this
36429 setContentSize : function(w, h){
36430 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
36431 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
36432 //if(!this.el.isBorderBox()){
36433 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
36434 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
36437 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
36438 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
36440 this.resizeTo(w, h);
36445 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
36446 * executed in response to a particular key being pressed while the dialog is active.
36447 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
36448 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
36449 * @param {Function} fn The function to call
36450 * @param {Object} scope (optional) The scope of the function
36451 * @return {Roo.BasicDialog} this
36453 addKeyListener : function(key, fn, scope){
36454 var keyCode, shift, ctrl, alt;
36455 if(typeof key == "object" && !(key instanceof Array)){
36456 keyCode = key["key"];
36457 shift = key["shift"];
36458 ctrl = key["ctrl"];
36463 var handler = function(dlg, e){
36464 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
36465 var k = e.getKey();
36466 if(keyCode instanceof Array){
36467 for(var i = 0, len = keyCode.length; i < len; i++){
36468 if(keyCode[i] == k){
36469 fn.call(scope || window, dlg, k, e);
36475 fn.call(scope || window, dlg, k, e);
36480 this.on("keydown", handler);
36485 * Returns the TabPanel component (creates it if it doesn't exist).
36486 * Note: If you wish to simply check for the existence of tabs without creating them,
36487 * check for a null 'tabs' property.
36488 * @return {Roo.TabPanel} The tabs component
36490 getTabs : function(){
36492 this.el.addClass("x-dlg-auto-tabs");
36493 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
36494 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
36500 * Adds a button to the footer section of the dialog.
36501 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
36502 * object or a valid Roo.DomHelper element config
36503 * @param {Function} handler The function called when the button is clicked
36504 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
36505 * @return {Roo.Button} The new button
36507 addButton : function(config, handler, scope){
36508 var dh = Roo.DomHelper;
36510 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
36512 if(!this.btnContainer){
36513 var tb = this.footer.createChild({
36515 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
36516 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
36518 this.btnContainer = tb.firstChild.firstChild.firstChild;
36523 minWidth: this.minButtonWidth,
36526 if(typeof config == "string"){
36527 bconfig.text = config;
36530 bconfig.dhconfig = config;
36532 Roo.apply(bconfig, config);
36536 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
36537 bconfig.position = Math.max(0, bconfig.position);
36538 fc = this.btnContainer.childNodes[bconfig.position];
36541 var btn = new Roo.Button(
36543 this.btnContainer.insertBefore(document.createElement("td"),fc)
36544 : this.btnContainer.appendChild(document.createElement("td")),
36545 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
36548 this.syncBodyHeight();
36551 * Array of all the buttons that have been added to this dialog via addButton
36556 this.buttons.push(btn);
36561 * Sets the default button to be focused when the dialog is displayed.
36562 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
36563 * @return {Roo.BasicDialog} this
36565 setDefaultButton : function(btn){
36566 this.defaultButton = btn;
36571 getHeaderFooterHeight : function(safe){
36574 height += this.header.getHeight();
36577 var fm = this.footer.getMargins();
36578 height += (this.footer.getHeight()+fm.top+fm.bottom);
36580 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
36581 height += this.centerBg.getPadding("tb");
36586 syncBodyHeight : function()
36588 var bd = this.body, // the text
36589 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
36591 var height = this.size.height - this.getHeaderFooterHeight(false);
36592 bd.setHeight(height-bd.getMargins("tb"));
36593 var hh = this.header.getHeight();
36594 var h = this.size.height-hh;
36597 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
36598 bw.setHeight(h-cb.getPadding("tb"));
36600 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
36601 bd.setWidth(bw.getWidth(true));
36603 this.tabs.syncHeight();
36605 this.tabs.el.repaint();
36611 * Restores the previous state of the dialog if Roo.state is configured.
36612 * @return {Roo.BasicDialog} this
36614 restoreState : function(){
36615 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
36616 if(box && box.width){
36617 this.xy = [box.x, box.y];
36618 this.resizeTo(box.width, box.height);
36624 beforeShow : function(){
36626 if(this.fixedcenter){
36627 this.xy = this.el.getCenterXY(true);
36630 Roo.get(document.body).addClass("x-body-masked");
36631 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
36634 this.constrainXY();
36638 animShow : function(){
36639 var b = Roo.get(this.animateTarget).getBox();
36640 this.proxy.setSize(b.width, b.height);
36641 this.proxy.setLocation(b.x, b.y);
36643 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
36644 true, .35, this.showEl.createDelegate(this));
36648 * Shows the dialog.
36649 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
36650 * @return {Roo.BasicDialog} this
36652 show : function(animateTarget){
36653 if (this.fireEvent("beforeshow", this) === false){
36656 if(this.syncHeightBeforeShow){
36657 this.syncBodyHeight();
36658 }else if(this.firstShow){
36659 this.firstShow = false;
36660 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
36662 this.animateTarget = animateTarget || this.animateTarget;
36663 if(!this.el.isVisible()){
36665 if(this.animateTarget && Roo.get(this.animateTarget)){
36675 showEl : function(){
36677 this.el.setXY(this.xy);
36679 this.adjustAssets(true);
36682 // IE peekaboo bug - fix found by Dave Fenwick
36686 this.fireEvent("show", this);
36690 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
36691 * dialog itself will receive focus.
36693 focus : function(){
36694 if(this.defaultButton){
36695 this.defaultButton.focus();
36697 this.focusEl.focus();
36702 constrainXY : function(){
36703 if(this.constraintoviewport !== false){
36704 if(!this.viewSize){
36705 if(this.container){
36706 var s = this.container.getSize();
36707 this.viewSize = [s.width, s.height];
36709 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
36712 var s = Roo.get(this.container||document).getScroll();
36714 var x = this.xy[0], y = this.xy[1];
36715 var w = this.size.width, h = this.size.height;
36716 var vw = this.viewSize[0], vh = this.viewSize[1];
36717 // only move it if it needs it
36719 // first validate right/bottom
36720 if(x + w > vw+s.left){
36724 if(y + h > vh+s.top){
36728 // then make sure top/left isn't negative
36740 if(this.isVisible()){
36741 this.el.setLocation(x, y);
36742 this.adjustAssets();
36749 onDrag : function(){
36750 if(!this.proxyDrag){
36751 this.xy = this.el.getXY();
36752 this.adjustAssets();
36757 adjustAssets : function(doShow){
36758 var x = this.xy[0], y = this.xy[1];
36759 var w = this.size.width, h = this.size.height;
36760 if(doShow === true){
36762 this.shadow.show(this.el);
36768 if(this.shadow && this.shadow.isVisible()){
36769 this.shadow.show(this.el);
36771 if(this.shim && this.shim.isVisible()){
36772 this.shim.setBounds(x, y, w, h);
36777 adjustViewport : function(w, h){
36779 w = Roo.lib.Dom.getViewWidth();
36780 h = Roo.lib.Dom.getViewHeight();
36783 this.viewSize = [w, h];
36784 if(this.modal && this.mask.isVisible()){
36785 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
36786 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
36788 if(this.isVisible()){
36789 this.constrainXY();
36794 * Destroys this dialog and all its supporting elements (including any tabs, shim,
36795 * shadow, proxy, mask, etc.) Also removes all event listeners.
36796 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
36798 destroy : function(removeEl){
36799 if(this.isVisible()){
36800 this.animateTarget = null;
36803 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
36805 this.tabs.destroy(removeEl);
36818 for(var i = 0, len = this.buttons.length; i < len; i++){
36819 this.buttons[i].destroy();
36822 this.el.removeAllListeners();
36823 if(removeEl === true){
36824 this.el.update("");
36827 Roo.DialogManager.unregister(this);
36831 startMove : function(){
36832 if(this.proxyDrag){
36835 if(this.constraintoviewport !== false){
36836 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
36841 endMove : function(){
36842 if(!this.proxyDrag){
36843 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
36845 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
36848 this.refreshSize();
36849 this.adjustAssets();
36851 this.fireEvent("move", this, this.xy[0], this.xy[1]);
36855 * Brings this dialog to the front of any other visible dialogs
36856 * @return {Roo.BasicDialog} this
36858 toFront : function(){
36859 Roo.DialogManager.bringToFront(this);
36864 * Sends this dialog to the back (under) of any other visible dialogs
36865 * @return {Roo.BasicDialog} this
36867 toBack : function(){
36868 Roo.DialogManager.sendToBack(this);
36873 * Centers this dialog in the viewport
36874 * @return {Roo.BasicDialog} this
36876 center : function(){
36877 var xy = this.el.getCenterXY(true);
36878 this.moveTo(xy[0], xy[1]);
36883 * Moves the dialog's top-left corner to the specified point
36884 * @param {Number} x
36885 * @param {Number} y
36886 * @return {Roo.BasicDialog} this
36888 moveTo : function(x, y){
36890 if(this.isVisible()){
36891 this.el.setXY(this.xy);
36892 this.adjustAssets();
36898 * Aligns the dialog to the specified element
36899 * @param {String/HTMLElement/Roo.Element} element The element to align to.
36900 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
36901 * @param {Array} offsets (optional) Offset the positioning by [x, y]
36902 * @return {Roo.BasicDialog} this
36904 alignTo : function(element, position, offsets){
36905 this.xy = this.el.getAlignToXY(element, position, offsets);
36906 if(this.isVisible()){
36907 this.el.setXY(this.xy);
36908 this.adjustAssets();
36914 * Anchors an element to another element and realigns it when the window is resized.
36915 * @param {String/HTMLElement/Roo.Element} element The element to align to.
36916 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
36917 * @param {Array} offsets (optional) Offset the positioning by [x, y]
36918 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
36919 * is a number, it is used as the buffer delay (defaults to 50ms).
36920 * @return {Roo.BasicDialog} this
36922 anchorTo : function(el, alignment, offsets, monitorScroll){
36923 var action = function(){
36924 this.alignTo(el, alignment, offsets);
36926 Roo.EventManager.onWindowResize(action, this);
36927 var tm = typeof monitorScroll;
36928 if(tm != 'undefined'){
36929 Roo.EventManager.on(window, 'scroll', action, this,
36930 {buffer: tm == 'number' ? monitorScroll : 50});
36937 * Returns true if the dialog is visible
36938 * @return {Boolean}
36940 isVisible : function(){
36941 return this.el.isVisible();
36945 animHide : function(callback){
36946 var b = Roo.get(this.animateTarget).getBox();
36948 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
36950 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
36951 this.hideEl.createDelegate(this, [callback]));
36955 * Hides the dialog.
36956 * @param {Function} callback (optional) Function to call when the dialog is hidden
36957 * @return {Roo.BasicDialog} this
36959 hide : function(callback){
36960 if (this.fireEvent("beforehide", this) === false){
36964 this.shadow.hide();
36969 // sometimes animateTarget seems to get set.. causing problems...
36970 // this just double checks..
36971 if(this.animateTarget && Roo.get(this.animateTarget)) {
36972 this.animHide(callback);
36975 this.hideEl(callback);
36981 hideEl : function(callback){
36985 Roo.get(document.body).removeClass("x-body-masked");
36987 this.fireEvent("hide", this);
36988 if(typeof callback == "function"){
36994 hideAction : function(){
36995 this.setLeft("-10000px");
36996 this.setTop("-10000px");
36997 this.setStyle("visibility", "hidden");
37001 refreshSize : function(){
37002 this.size = this.el.getSize();
37003 this.xy = this.el.getXY();
37004 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
37008 // z-index is managed by the DialogManager and may be overwritten at any time
37009 setZIndex : function(index){
37011 this.mask.setStyle("z-index", index);
37014 this.shim.setStyle("z-index", ++index);
37017 this.shadow.setZIndex(++index);
37019 this.el.setStyle("z-index", ++index);
37021 this.proxy.setStyle("z-index", ++index);
37024 this.resizer.proxy.setStyle("z-index", ++index);
37027 this.lastZIndex = index;
37031 * Returns the element for this dialog
37032 * @return {Roo.Element} The underlying dialog Element
37034 getEl : function(){
37040 * @class Roo.DialogManager
37041 * Provides global access to BasicDialogs that have been created and
37042 * support for z-indexing (layering) multiple open dialogs.
37044 Roo.DialogManager = function(){
37046 var accessList = [];
37050 var sortDialogs = function(d1, d2){
37051 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
37055 var orderDialogs = function(){
37056 accessList.sort(sortDialogs);
37057 var seed = Roo.DialogManager.zseed;
37058 for(var i = 0, len = accessList.length; i < len; i++){
37059 var dlg = accessList[i];
37061 dlg.setZIndex(seed + (i*10));
37068 * The starting z-index for BasicDialogs (defaults to 9000)
37069 * @type Number The z-index value
37074 register : function(dlg){
37075 list[dlg.id] = dlg;
37076 accessList.push(dlg);
37080 unregister : function(dlg){
37081 delete list[dlg.id];
37084 if(!accessList.indexOf){
37085 for( i = 0, len = accessList.length; i < len; i++){
37086 if(accessList[i] == dlg){
37087 accessList.splice(i, 1);
37092 i = accessList.indexOf(dlg);
37094 accessList.splice(i, 1);
37100 * Gets a registered dialog by id
37101 * @param {String/Object} id The id of the dialog or a dialog
37102 * @return {Roo.BasicDialog} this
37104 get : function(id){
37105 return typeof id == "object" ? id : list[id];
37109 * Brings the specified dialog to the front
37110 * @param {String/Object} dlg The id of the dialog or a dialog
37111 * @return {Roo.BasicDialog} this
37113 bringToFront : function(dlg){
37114 dlg = this.get(dlg);
37117 dlg._lastAccess = new Date().getTime();
37124 * Sends the specified dialog to the back
37125 * @param {String/Object} dlg The id of the dialog or a dialog
37126 * @return {Roo.BasicDialog} this
37128 sendToBack : function(dlg){
37129 dlg = this.get(dlg);
37130 dlg._lastAccess = -(new Date().getTime());
37136 * Hides all dialogs
37138 hideAll : function(){
37139 for(var id in list){
37140 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
37149 * @class Roo.LayoutDialog
37150 * @extends Roo.BasicDialog
37151 * Dialog which provides adjustments for working with a layout in a Dialog.
37152 * Add your necessary layout config options to the dialog's config.<br>
37153 * Example usage (including a nested layout):
37156 dialog = new Roo.LayoutDialog("download-dlg", {
37165 // layout config merges with the dialog config
37167 tabPosition: "top",
37168 alwaysShowTabs: true
37171 dialog.addKeyListener(27, dialog.hide, dialog);
37172 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
37173 dialog.addButton("Build It!", this.getDownload, this);
37175 // we can even add nested layouts
37176 var innerLayout = new Roo.BorderLayout("dl-inner", {
37186 innerLayout.beginUpdate();
37187 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
37188 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
37189 innerLayout.endUpdate(true);
37191 var layout = dialog.getLayout();
37192 layout.beginUpdate();
37193 layout.add("center", new Roo.ContentPanel("standard-panel",
37194 {title: "Download the Source", fitToFrame:true}));
37195 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
37196 {title: "Build your own roo.js"}));
37197 layout.getRegion("center").showPanel(sp);
37198 layout.endUpdate();
37202 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
37203 * @param {Object} config configuration options
37205 Roo.LayoutDialog = function(el, cfg){
37208 if (typeof(cfg) == 'undefined') {
37209 config = Roo.apply({}, el);
37210 // not sure why we use documentElement here.. - it should always be body.
37211 // IE7 borks horribly if we use documentElement.
37212 // webkit also does not like documentElement - it creates a body element...
37213 el = Roo.get( document.body || document.documentElement ).createChild();
37214 //config.autoCreate = true;
37218 config.autoTabs = false;
37219 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
37220 this.body.setStyle({overflow:"hidden", position:"relative"});
37221 this.layout = new Roo.BorderLayout(this.body.dom, config);
37222 this.layout.monitorWindowResize = false;
37223 this.el.addClass("x-dlg-auto-layout");
37224 // fix case when center region overwrites center function
37225 this.center = Roo.BasicDialog.prototype.center;
37226 this.on("show", this.layout.layout, this.layout, true);
37227 if (config.items) {
37228 var xitems = config.items;
37229 delete config.items;
37230 Roo.each(xitems, this.addxtype, this);
37235 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
37237 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
37240 endUpdate : function(){
37241 this.layout.endUpdate();
37245 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
37248 beginUpdate : function(){
37249 this.layout.beginUpdate();
37253 * Get the BorderLayout for this dialog
37254 * @return {Roo.BorderLayout}
37256 getLayout : function(){
37257 return this.layout;
37260 showEl : function(){
37261 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
37263 this.layout.layout();
37268 // Use the syncHeightBeforeShow config option to control this automatically
37269 syncBodyHeight : function(){
37270 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
37271 if(this.layout){this.layout.layout();}
37275 * Add an xtype element (actually adds to the layout.)
37276 * @return {Object} xdata xtype object data.
37279 addxtype : function(c) {
37280 return this.layout.addxtype(c);
37284 * Ext JS Library 1.1.1
37285 * Copyright(c) 2006-2007, Ext JS, LLC.
37287 * Originally Released Under LGPL - original licence link has changed is not relivant.
37290 * <script type="text/javascript">
37294 * @class Roo.MessageBox
37295 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
37299 Roo.Msg.alert('Status', 'Changes saved successfully.');
37301 // Prompt for user data:
37302 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
37304 // process text value...
37308 // Show a dialog using config options:
37310 title:'Save Changes?',
37311 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
37312 buttons: Roo.Msg.YESNOCANCEL,
37319 Roo.MessageBox = function(){
37320 var dlg, opt, mask, waitTimer;
37321 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
37322 var buttons, activeTextEl, bwidth;
37325 var handleButton = function(button){
37327 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
37331 var handleHide = function(){
37332 if(opt && opt.cls){
37333 dlg.el.removeClass(opt.cls);
37336 Roo.TaskMgr.stop(waitTimer);
37342 var updateButtons = function(b){
37345 buttons["ok"].hide();
37346 buttons["cancel"].hide();
37347 buttons["yes"].hide();
37348 buttons["no"].hide();
37349 dlg.footer.dom.style.display = 'none';
37352 dlg.footer.dom.style.display = '';
37353 for(var k in buttons){
37354 if(typeof buttons[k] != "function"){
37357 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
37358 width += buttons[k].el.getWidth()+15;
37368 var handleEsc = function(d, k, e){
37369 if(opt && opt.closable !== false){
37379 * Returns a reference to the underlying {@link Roo.BasicDialog} element
37380 * @return {Roo.BasicDialog} The BasicDialog element
37382 getDialog : function(){
37384 dlg = new Roo.BasicDialog("x-msg-box", {
37389 constraintoviewport:false,
37391 collapsible : false,
37394 width:400, height:100,
37395 buttonAlign:"center",
37396 closeClick : function(){
37397 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
37398 handleButton("no");
37400 handleButton("cancel");
37404 dlg.on("hide", handleHide);
37406 dlg.addKeyListener(27, handleEsc);
37408 var bt = this.buttonText;
37409 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
37410 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
37411 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
37412 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
37413 bodyEl = dlg.body.createChild({
37415 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>'
37417 msgEl = bodyEl.dom.firstChild;
37418 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
37419 textboxEl.enableDisplayMode();
37420 textboxEl.addKeyListener([10,13], function(){
37421 if(dlg.isVisible() && opt && opt.buttons){
37422 if(opt.buttons.ok){
37423 handleButton("ok");
37424 }else if(opt.buttons.yes){
37425 handleButton("yes");
37429 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
37430 textareaEl.enableDisplayMode();
37431 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
37432 progressEl.enableDisplayMode();
37433 var pf = progressEl.dom.firstChild;
37435 pp = Roo.get(pf.firstChild);
37436 pp.setHeight(pf.offsetHeight);
37444 * Updates the message box body text
37445 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
37446 * the XHTML-compliant non-breaking space character '&#160;')
37447 * @return {Roo.MessageBox} This message box
37449 updateText : function(text){
37450 if(!dlg.isVisible() && !opt.width){
37451 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
37453 msgEl.innerHTML = text || ' ';
37455 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
37456 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
37458 Math.min(opt.width || cw , this.maxWidth),
37459 Math.max(opt.minWidth || this.minWidth, bwidth)
37462 activeTextEl.setWidth(w);
37464 if(dlg.isVisible()){
37465 dlg.fixedcenter = false;
37467 // to big, make it scroll. = But as usual stupid IE does not support
37470 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
37471 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
37472 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
37474 bodyEl.dom.style.height = '';
37475 bodyEl.dom.style.overflowY = '';
37478 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
37480 bodyEl.dom.style.overflowX = '';
37483 dlg.setContentSize(w, bodyEl.getHeight());
37484 if(dlg.isVisible()){
37485 dlg.fixedcenter = true;
37491 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
37492 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
37493 * @param {Number} value Any number between 0 and 1 (e.g., .5)
37494 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
37495 * @return {Roo.MessageBox} This message box
37497 updateProgress : function(value, text){
37499 this.updateText(text);
37501 if (pp) { // weird bug on my firefox - for some reason this is not defined
37502 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
37508 * Returns true if the message box is currently displayed
37509 * @return {Boolean} True if the message box is visible, else false
37511 isVisible : function(){
37512 return dlg && dlg.isVisible();
37516 * Hides the message box if it is displayed
37519 if(this.isVisible()){
37525 * Displays a new message box, or reinitializes an existing message box, based on the config options
37526 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
37527 * The following config object properties are supported:
37529 Property Type Description
37530 ---------- --------------- ------------------------------------------------------------------------------------
37531 animEl String/Element An id or Element from which the message box should animate as it opens and
37532 closes (defaults to undefined)
37533 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
37534 cancel:'Bar'}), or false to not show any buttons (defaults to false)
37535 closable Boolean False to hide the top-right close button (defaults to true). Note that
37536 progress and wait dialogs will ignore this property and always hide the
37537 close button as they can only be closed programmatically.
37538 cls String A custom CSS class to apply to the message box element
37539 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
37540 displayed (defaults to 75)
37541 fn Function A callback function to execute after closing the dialog. The arguments to the
37542 function will be btn (the name of the button that was clicked, if applicable,
37543 e.g. "ok"), and text (the value of the active text field, if applicable).
37544 Progress and wait dialogs will ignore this option since they do not respond to
37545 user actions and can only be closed programmatically, so any required function
37546 should be called by the same code after it closes the dialog.
37547 icon String A CSS class that provides a background image to be used as an icon for
37548 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
37549 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
37550 minWidth Number The minimum width in pixels of the message box (defaults to 100)
37551 modal Boolean False to allow user interaction with the page while the message box is
37552 displayed (defaults to true)
37553 msg String A string that will replace the existing message box body text (defaults
37554 to the XHTML-compliant non-breaking space character ' ')
37555 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
37556 progress Boolean True to display a progress bar (defaults to false)
37557 progressText String The text to display inside the progress bar if progress = true (defaults to '')
37558 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
37559 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
37560 title String The title text
37561 value String The string value to set into the active textbox element if displayed
37562 wait Boolean True to display a progress bar (defaults to false)
37563 width Number The width of the dialog in pixels
37570 msg: 'Please enter your address:',
37572 buttons: Roo.MessageBox.OKCANCEL,
37575 animEl: 'addAddressBtn'
37578 * @param {Object} config Configuration options
37579 * @return {Roo.MessageBox} This message box
37581 show : function(options)
37584 // this causes nightmares if you show one dialog after another
37585 // especially on callbacks..
37587 if(this.isVisible()){
37590 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
37591 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
37592 Roo.log("New Dialog Message:" + options.msg )
37593 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
37594 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
37597 var d = this.getDialog();
37599 d.setTitle(opt.title || " ");
37600 d.close.setDisplayed(opt.closable !== false);
37601 activeTextEl = textboxEl;
37602 opt.prompt = opt.prompt || (opt.multiline ? true : false);
37607 textareaEl.setHeight(typeof opt.multiline == "number" ?
37608 opt.multiline : this.defaultTextHeight);
37609 activeTextEl = textareaEl;
37618 progressEl.setDisplayed(opt.progress === true);
37619 this.updateProgress(0);
37620 activeTextEl.dom.value = opt.value || "";
37622 dlg.setDefaultButton(activeTextEl);
37624 var bs = opt.buttons;
37627 db = buttons["ok"];
37628 }else if(bs && bs.yes){
37629 db = buttons["yes"];
37631 dlg.setDefaultButton(db);
37633 bwidth = updateButtons(opt.buttons);
37634 this.updateText(opt.msg);
37636 d.el.addClass(opt.cls);
37638 d.proxyDrag = opt.proxyDrag === true;
37639 d.modal = opt.modal !== false;
37640 d.mask = opt.modal !== false ? mask : false;
37641 if(!d.isVisible()){
37642 // force it to the end of the z-index stack so it gets a cursor in FF
37643 document.body.appendChild(dlg.el.dom);
37644 d.animateTarget = null;
37645 d.show(options.animEl);
37651 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
37652 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
37653 * and closing the message box when the process is complete.
37654 * @param {String} title The title bar text
37655 * @param {String} msg The message box body text
37656 * @return {Roo.MessageBox} This message box
37658 progress : function(title, msg){
37665 minWidth: this.minProgressWidth,
37672 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
37673 * If a callback function is passed it will be called after the user clicks the button, and the
37674 * id of the button that was clicked will be passed as the only parameter to the callback
37675 * (could also be the top-right close button).
37676 * @param {String} title The title bar text
37677 * @param {String} msg The message box body text
37678 * @param {Function} fn (optional) The callback function invoked after the message box is closed
37679 * @param {Object} scope (optional) The scope of the callback function
37680 * @return {Roo.MessageBox} This message box
37682 alert : function(title, msg, fn, scope){
37695 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
37696 * interaction while waiting for a long-running process to complete that does not have defined intervals.
37697 * You are responsible for closing the message box when the process is complete.
37698 * @param {String} msg The message box body text
37699 * @param {String} title (optional) The title bar text
37700 * @return {Roo.MessageBox} This message box
37702 wait : function(msg, title){
37713 waitTimer = Roo.TaskMgr.start({
37715 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
37723 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
37724 * If a callback function is passed it will be called after the user clicks either button, and the id of the
37725 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
37726 * @param {String} title The title bar text
37727 * @param {String} msg The message box body text
37728 * @param {Function} fn (optional) The callback function invoked after the message box is closed
37729 * @param {Object} scope (optional) The scope of the callback function
37730 * @return {Roo.MessageBox} This message box
37732 confirm : function(title, msg, fn, scope){
37736 buttons: this.YESNO,
37745 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
37746 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
37747 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
37748 * (could also be the top-right close button) and the text that was entered will be passed as the two
37749 * parameters to the callback.
37750 * @param {String} title The title bar text
37751 * @param {String} msg The message box body text
37752 * @param {Function} fn (optional) The callback function invoked after the message box is closed
37753 * @param {Object} scope (optional) The scope of the callback function
37754 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
37755 * property, or the height in pixels to create the textbox (defaults to false / single-line)
37756 * @return {Roo.MessageBox} This message box
37758 prompt : function(title, msg, fn, scope, multiline){
37762 buttons: this.OKCANCEL,
37767 multiline: multiline,
37774 * Button config that displays a single OK button
37779 * Button config that displays Yes and No buttons
37782 YESNO : {yes:true, no:true},
37784 * Button config that displays OK and Cancel buttons
37787 OKCANCEL : {ok:true, cancel:true},
37789 * Button config that displays Yes, No and Cancel buttons
37792 YESNOCANCEL : {yes:true, no:true, cancel:true},
37795 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
37798 defaultTextHeight : 75,
37800 * The maximum width in pixels of the message box (defaults to 600)
37805 * The minimum width in pixels of the message box (defaults to 100)
37810 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
37811 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
37814 minProgressWidth : 250,
37816 * An object containing the default button text strings that can be overriden for localized language support.
37817 * Supported properties are: ok, cancel, yes and no.
37818 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
37831 * Shorthand for {@link Roo.MessageBox}
37833 Roo.Msg = Roo.MessageBox;/*
37835 * Ext JS Library 1.1.1
37836 * Copyright(c) 2006-2007, Ext JS, LLC.
37838 * Originally Released Under LGPL - original licence link has changed is not relivant.
37841 * <script type="text/javascript">
37844 * @class Roo.QuickTips
37845 * Provides attractive and customizable tooltips for any element.
37848 Roo.QuickTips = function(){
37849 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
37850 var ce, bd, xy, dd;
37851 var visible = false, disabled = true, inited = false;
37852 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
37854 var onOver = function(e){
37858 var t = e.getTarget();
37859 if(!t || t.nodeType !== 1 || t == document || t == document.body){
37862 if(ce && t == ce.el){
37863 clearTimeout(hideProc);
37866 if(t && tagEls[t.id]){
37867 tagEls[t.id].el = t;
37868 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
37871 var ttp, et = Roo.fly(t);
37872 var ns = cfg.namespace;
37873 if(tm.interceptTitles && t.title){
37876 t.removeAttribute("title");
37877 e.preventDefault();
37879 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
37882 showProc = show.defer(tm.showDelay, tm, [{
37885 width: et.getAttributeNS(ns, cfg.width),
37886 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
37887 title: et.getAttributeNS(ns, cfg.title),
37888 cls: et.getAttributeNS(ns, cfg.cls)
37893 var onOut = function(e){
37894 clearTimeout(showProc);
37895 var t = e.getTarget();
37896 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
37897 hideProc = setTimeout(hide, tm.hideDelay);
37901 var onMove = function(e){
37907 if(tm.trackMouse && ce){
37912 var onDown = function(e){
37913 clearTimeout(showProc);
37914 clearTimeout(hideProc);
37916 if(tm.hideOnClick){
37919 tm.enable.defer(100, tm);
37924 var getPad = function(){
37925 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
37928 var show = function(o){
37932 clearTimeout(dismissProc);
37934 if(removeCls){ // in case manually hidden
37935 el.removeClass(removeCls);
37939 el.addClass(ce.cls);
37940 removeCls = ce.cls;
37943 tipTitle.update(ce.title);
37946 tipTitle.update('');
37949 el.dom.style.width = tm.maxWidth+'px';
37950 //tipBody.dom.style.width = '';
37951 tipBodyText.update(o.text);
37952 var p = getPad(), w = ce.width;
37954 var td = tipBodyText.dom;
37955 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
37956 if(aw > tm.maxWidth){
37958 }else if(aw < tm.minWidth){
37964 //tipBody.setWidth(w);
37965 el.setWidth(parseInt(w, 10) + p);
37966 if(ce.autoHide === false){
37967 close.setDisplayed(true);
37972 close.setDisplayed(false);
37978 el.avoidY = xy[1]-18;
37983 el.setStyle("visibility", "visible");
37984 el.fadeIn({callback: afterShow});
37990 var afterShow = function(){
37994 if(tm.autoDismiss && ce.autoHide !== false){
37995 dismissProc = setTimeout(hide, tm.autoDismissDelay);
38000 var hide = function(noanim){
38001 clearTimeout(dismissProc);
38002 clearTimeout(hideProc);
38004 if(el.isVisible()){
38006 if(noanim !== true && tm.animate){
38007 el.fadeOut({callback: afterHide});
38014 var afterHide = function(){
38017 el.removeClass(removeCls);
38024 * @cfg {Number} minWidth
38025 * The minimum width of the quick tip (defaults to 40)
38029 * @cfg {Number} maxWidth
38030 * The maximum width of the quick tip (defaults to 300)
38034 * @cfg {Boolean} interceptTitles
38035 * True to automatically use the element's DOM title value if available (defaults to false)
38037 interceptTitles : false,
38039 * @cfg {Boolean} trackMouse
38040 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
38042 trackMouse : false,
38044 * @cfg {Boolean} hideOnClick
38045 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
38047 hideOnClick : true,
38049 * @cfg {Number} showDelay
38050 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
38054 * @cfg {Number} hideDelay
38055 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
38059 * @cfg {Boolean} autoHide
38060 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
38061 * Used in conjunction with hideDelay.
38066 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
38067 * (defaults to true). Used in conjunction with autoDismissDelay.
38069 autoDismiss : true,
38072 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
38074 autoDismissDelay : 5000,
38076 * @cfg {Boolean} animate
38077 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
38082 * @cfg {String} title
38083 * Title text to display (defaults to ''). This can be any valid HTML markup.
38087 * @cfg {String} text
38088 * Body text to display (defaults to ''). This can be any valid HTML markup.
38092 * @cfg {String} cls
38093 * A CSS class to apply to the base quick tip element (defaults to '').
38097 * @cfg {Number} width
38098 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
38099 * minWidth or maxWidth.
38104 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
38105 * or display QuickTips in a page.
38108 tm = Roo.QuickTips;
38109 cfg = tm.tagConfig;
38111 if(!Roo.isReady){ // allow calling of init() before onReady
38112 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
38115 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
38116 el.fxDefaults = {stopFx: true};
38117 // maximum custom styling
38118 //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>');
38119 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>');
38120 tipTitle = el.child('h3');
38121 tipTitle.enableDisplayMode("block");
38122 tipBody = el.child('div.x-tip-bd');
38123 tipBodyText = el.child('div.x-tip-bd-inner');
38124 //bdLeft = el.child('div.x-tip-bd-left');
38125 //bdRight = el.child('div.x-tip-bd-right');
38126 close = el.child('div.x-tip-close');
38127 close.enableDisplayMode("block");
38128 close.on("click", hide);
38129 var d = Roo.get(document);
38130 d.on("mousedown", onDown);
38131 d.on("mouseover", onOver);
38132 d.on("mouseout", onOut);
38133 d.on("mousemove", onMove);
38134 esc = d.addKeyListener(27, hide);
38137 dd = el.initDD("default", null, {
38138 onDrag : function(){
38142 dd.setHandleElId(tipTitle.id);
38151 * Configures a new quick tip instance and assigns it to a target element. The following config options
38154 Property Type Description
38155 ---------- --------------------- ------------------------------------------------------------------------
38156 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
38158 * @param {Object} config The config object
38160 register : function(config){
38161 var cs = config instanceof Array ? config : arguments;
38162 for(var i = 0, len = cs.length; i < len; i++) {
38164 var target = c.target;
38166 if(target instanceof Array){
38167 for(var j = 0, jlen = target.length; j < jlen; j++){
38168 tagEls[target[j]] = c;
38171 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
38178 * Removes this quick tip from its element and destroys it.
38179 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
38181 unregister : function(el){
38182 delete tagEls[Roo.id(el)];
38186 * Enable this quick tip.
38188 enable : function(){
38189 if(inited && disabled){
38191 if(locks.length < 1){
38198 * Disable this quick tip.
38200 disable : function(){
38202 clearTimeout(showProc);
38203 clearTimeout(hideProc);
38204 clearTimeout(dismissProc);
38212 * Returns true if the quick tip is enabled, else false.
38214 isEnabled : function(){
38220 namespace : "roo", // was ext?? this may break..
38221 alt_namespace : "ext",
38222 attribute : "qtip",
38232 // backwards compat
38233 Roo.QuickTips.tips = Roo.QuickTips.register;/*
38235 * Ext JS Library 1.1.1
38236 * Copyright(c) 2006-2007, Ext JS, LLC.
38238 * Originally Released Under LGPL - original licence link has changed is not relivant.
38241 * <script type="text/javascript">
38246 * @class Roo.tree.TreePanel
38247 * @extends Roo.data.Tree
38249 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
38250 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
38251 * @cfg {Boolean} enableDD true to enable drag and drop
38252 * @cfg {Boolean} enableDrag true to enable just drag
38253 * @cfg {Boolean} enableDrop true to enable just drop
38254 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
38255 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
38256 * @cfg {String} ddGroup The DD group this TreePanel belongs to
38257 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
38258 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
38259 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
38260 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
38261 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
38262 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
38263 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
38264 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
38265 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
38266 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
38267 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
38268 * @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>
38269 * @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>
38272 * @param {String/HTMLElement/Element} el The container element
38273 * @param {Object} config
38275 Roo.tree.TreePanel = function(el, config){
38277 var loader = false;
38279 root = config.root;
38280 delete config.root;
38282 if (config.loader) {
38283 loader = config.loader;
38284 delete config.loader;
38287 Roo.apply(this, config);
38288 Roo.tree.TreePanel.superclass.constructor.call(this);
38289 this.el = Roo.get(el);
38290 this.el.addClass('x-tree');
38291 //console.log(root);
38293 this.setRootNode( Roo.factory(root, Roo.tree));
38296 this.loader = Roo.factory(loader, Roo.tree);
38299 * Read-only. The id of the container element becomes this TreePanel's id.
38301 this.id = this.el.id;
38304 * @event beforeload
38305 * Fires before a node is loaded, return false to cancel
38306 * @param {Node} node The node being loaded
38308 "beforeload" : true,
38311 * Fires when a node is loaded
38312 * @param {Node} node The node that was loaded
38316 * @event textchange
38317 * Fires when the text for a node is changed
38318 * @param {Node} node The node
38319 * @param {String} text The new text
38320 * @param {String} oldText The old text
38322 "textchange" : true,
38324 * @event beforeexpand
38325 * Fires before a node is expanded, return false to cancel.
38326 * @param {Node} node The node
38327 * @param {Boolean} deep
38328 * @param {Boolean} anim
38330 "beforeexpand" : true,
38332 * @event beforecollapse
38333 * Fires before a node is collapsed, return false to cancel.
38334 * @param {Node} node The node
38335 * @param {Boolean} deep
38336 * @param {Boolean} anim
38338 "beforecollapse" : true,
38341 * Fires when a node is expanded
38342 * @param {Node} node The node
38346 * @event disabledchange
38347 * Fires when the disabled status of a node changes
38348 * @param {Node} node The node
38349 * @param {Boolean} disabled
38351 "disabledchange" : true,
38354 * Fires when a node is collapsed
38355 * @param {Node} node The node
38359 * @event beforeclick
38360 * Fires before click processing on a node. Return false to cancel the default action.
38361 * @param {Node} node The node
38362 * @param {Roo.EventObject} e The event object
38364 "beforeclick":true,
38366 * @event checkchange
38367 * Fires when a node with a checkbox's checked property changes
38368 * @param {Node} this This node
38369 * @param {Boolean} checked
38371 "checkchange":true,
38374 * Fires when a node is clicked
38375 * @param {Node} node The node
38376 * @param {Roo.EventObject} e The event object
38381 * Fires when a node is double clicked
38382 * @param {Node} node The node
38383 * @param {Roo.EventObject} e The event object
38387 * @event contextmenu
38388 * Fires when a node is right clicked
38389 * @param {Node} node The node
38390 * @param {Roo.EventObject} e The event object
38392 "contextmenu":true,
38394 * @event beforechildrenrendered
38395 * Fires right before the child nodes for a node are rendered
38396 * @param {Node} node The node
38398 "beforechildrenrendered":true,
38401 * Fires when a node starts being dragged
38402 * @param {Roo.tree.TreePanel} this
38403 * @param {Roo.tree.TreeNode} node
38404 * @param {event} e The raw browser event
38406 "startdrag" : true,
38409 * Fires when a drag operation is complete
38410 * @param {Roo.tree.TreePanel} this
38411 * @param {Roo.tree.TreeNode} node
38412 * @param {event} e The raw browser event
38417 * Fires when a dragged node is dropped on a valid DD target
38418 * @param {Roo.tree.TreePanel} this
38419 * @param {Roo.tree.TreeNode} node
38420 * @param {DD} dd The dd it was dropped on
38421 * @param {event} e The raw browser event
38425 * @event beforenodedrop
38426 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
38427 * passed to handlers has the following properties:<br />
38428 * <ul style="padding:5px;padding-left:16px;">
38429 * <li>tree - The TreePanel</li>
38430 * <li>target - The node being targeted for the drop</li>
38431 * <li>data - The drag data from the drag source</li>
38432 * <li>point - The point of the drop - append, above or below</li>
38433 * <li>source - The drag source</li>
38434 * <li>rawEvent - Raw mouse event</li>
38435 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
38436 * to be inserted by setting them on this object.</li>
38437 * <li>cancel - Set this to true to cancel the drop.</li>
38439 * @param {Object} dropEvent
38441 "beforenodedrop" : true,
38444 * Fires after a DD object is dropped on a node in this tree. The dropEvent
38445 * passed to handlers has the following properties:<br />
38446 * <ul style="padding:5px;padding-left:16px;">
38447 * <li>tree - The TreePanel</li>
38448 * <li>target - The node being targeted for the drop</li>
38449 * <li>data - The drag data from the drag source</li>
38450 * <li>point - The point of the drop - append, above or below</li>
38451 * <li>source - The drag source</li>
38452 * <li>rawEvent - Raw mouse event</li>
38453 * <li>dropNode - Dropped node(s).</li>
38455 * @param {Object} dropEvent
38459 * @event nodedragover
38460 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
38461 * passed to handlers has the following properties:<br />
38462 * <ul style="padding:5px;padding-left:16px;">
38463 * <li>tree - The TreePanel</li>
38464 * <li>target - The node being targeted for the drop</li>
38465 * <li>data - The drag data from the drag source</li>
38466 * <li>point - The point of the drop - append, above or below</li>
38467 * <li>source - The drag source</li>
38468 * <li>rawEvent - Raw mouse event</li>
38469 * <li>dropNode - Drop node(s) provided by the source.</li>
38470 * <li>cancel - Set this to true to signal drop not allowed.</li>
38472 * @param {Object} dragOverEvent
38474 "nodedragover" : true
38477 if(this.singleExpand){
38478 this.on("beforeexpand", this.restrictExpand, this);
38481 this.editor.tree = this;
38482 this.editor = Roo.factory(this.editor, Roo.tree);
38485 if (this.selModel) {
38486 this.selModel = Roo.factory(this.selModel, Roo.tree);
38490 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
38491 rootVisible : true,
38492 animate: Roo.enableFx,
38495 hlDrop : Roo.enableFx,
38499 rendererTip: false,
38501 restrictExpand : function(node){
38502 var p = node.parentNode;
38504 if(p.expandedChild && p.expandedChild.parentNode == p){
38505 p.expandedChild.collapse();
38507 p.expandedChild = node;
38511 // private override
38512 setRootNode : function(node){
38513 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
38514 if(!this.rootVisible){
38515 node.ui = new Roo.tree.RootTreeNodeUI(node);
38521 * Returns the container element for this TreePanel
38523 getEl : function(){
38528 * Returns the default TreeLoader for this TreePanel
38530 getLoader : function(){
38531 return this.loader;
38537 expandAll : function(){
38538 this.root.expand(true);
38542 * Collapse all nodes
38544 collapseAll : function(){
38545 this.root.collapse(true);
38549 * Returns the selection model used by this TreePanel
38551 getSelectionModel : function(){
38552 if(!this.selModel){
38553 this.selModel = new Roo.tree.DefaultSelectionModel();
38555 return this.selModel;
38559 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
38560 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
38561 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
38564 getChecked : function(a, startNode){
38565 startNode = startNode || this.root;
38567 var f = function(){
38568 if(this.attributes.checked){
38569 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
38572 startNode.cascade(f);
38577 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
38578 * @param {String} path
38579 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
38580 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
38581 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
38583 expandPath : function(path, attr, callback){
38584 attr = attr || "id";
38585 var keys = path.split(this.pathSeparator);
38586 var curNode = this.root;
38587 if(curNode.attributes[attr] != keys[1]){ // invalid root
38589 callback(false, null);
38594 var f = function(){
38595 if(++index == keys.length){
38597 callback(true, curNode);
38601 var c = curNode.findChild(attr, keys[index]);
38604 callback(false, curNode);
38609 c.expand(false, false, f);
38611 curNode.expand(false, false, f);
38615 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
38616 * @param {String} path
38617 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
38618 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
38619 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
38621 selectPath : function(path, attr, callback){
38622 attr = attr || "id";
38623 var keys = path.split(this.pathSeparator);
38624 var v = keys.pop();
38625 if(keys.length > 0){
38626 var f = function(success, node){
38627 if(success && node){
38628 var n = node.findChild(attr, v);
38634 }else if(callback){
38635 callback(false, n);
38639 callback(false, n);
38643 this.expandPath(keys.join(this.pathSeparator), attr, f);
38645 this.root.select();
38647 callback(true, this.root);
38652 getTreeEl : function(){
38657 * Trigger rendering of this TreePanel
38659 render : function(){
38660 if (this.innerCt) {
38661 return this; // stop it rendering more than once!!
38664 this.innerCt = this.el.createChild({tag:"ul",
38665 cls:"x-tree-root-ct " +
38666 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
38668 if(this.containerScroll){
38669 Roo.dd.ScrollManager.register(this.el);
38671 if((this.enableDD || this.enableDrop) && !this.dropZone){
38673 * The dropZone used by this tree if drop is enabled
38674 * @type Roo.tree.TreeDropZone
38676 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
38677 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
38680 if((this.enableDD || this.enableDrag) && !this.dragZone){
38682 * The dragZone used by this tree if drag is enabled
38683 * @type Roo.tree.TreeDragZone
38685 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
38686 ddGroup: this.ddGroup || "TreeDD",
38687 scroll: this.ddScroll
38690 this.getSelectionModel().init(this);
38692 Roo.log("ROOT not set in tree");
38695 this.root.render();
38696 if(!this.rootVisible){
38697 this.root.renderChildren();
38703 * Ext JS Library 1.1.1
38704 * Copyright(c) 2006-2007, Ext JS, LLC.
38706 * Originally Released Under LGPL - original licence link has changed is not relivant.
38709 * <script type="text/javascript">
38714 * @class Roo.tree.DefaultSelectionModel
38715 * @extends Roo.util.Observable
38716 * The default single selection for a TreePanel.
38717 * @param {Object} cfg Configuration
38719 Roo.tree.DefaultSelectionModel = function(cfg){
38720 this.selNode = null;
38726 * @event selectionchange
38727 * Fires when the selected node changes
38728 * @param {DefaultSelectionModel} this
38729 * @param {TreeNode} node the new selection
38731 "selectionchange" : true,
38734 * @event beforeselect
38735 * Fires before the selected node changes, return false to cancel the change
38736 * @param {DefaultSelectionModel} this
38737 * @param {TreeNode} node the new selection
38738 * @param {TreeNode} node the old selection
38740 "beforeselect" : true
38743 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
38746 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
38747 init : function(tree){
38749 tree.getTreeEl().on("keydown", this.onKeyDown, this);
38750 tree.on("click", this.onNodeClick, this);
38753 onNodeClick : function(node, e){
38754 if (e.ctrlKey && this.selNode == node) {
38755 this.unselect(node);
38763 * @param {TreeNode} node The node to select
38764 * @return {TreeNode} The selected node
38766 select : function(node){
38767 var last = this.selNode;
38768 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
38770 last.ui.onSelectedChange(false);
38772 this.selNode = node;
38773 node.ui.onSelectedChange(true);
38774 this.fireEvent("selectionchange", this, node, last);
38781 * @param {TreeNode} node The node to unselect
38783 unselect : function(node){
38784 if(this.selNode == node){
38785 this.clearSelections();
38790 * Clear all selections
38792 clearSelections : function(){
38793 var n = this.selNode;
38795 n.ui.onSelectedChange(false);
38796 this.selNode = null;
38797 this.fireEvent("selectionchange", this, null);
38803 * Get the selected node
38804 * @return {TreeNode} The selected node
38806 getSelectedNode : function(){
38807 return this.selNode;
38811 * Returns true if the node is selected
38812 * @param {TreeNode} node The node to check
38813 * @return {Boolean}
38815 isSelected : function(node){
38816 return this.selNode == node;
38820 * Selects the node above the selected node in the tree, intelligently walking the nodes
38821 * @return TreeNode The new selection
38823 selectPrevious : function(){
38824 var s = this.selNode || this.lastSelNode;
38828 var ps = s.previousSibling;
38830 if(!ps.isExpanded() || ps.childNodes.length < 1){
38831 return this.select(ps);
38833 var lc = ps.lastChild;
38834 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
38837 return this.select(lc);
38839 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
38840 return this.select(s.parentNode);
38846 * Selects the node above the selected node in the tree, intelligently walking the nodes
38847 * @return TreeNode The new selection
38849 selectNext : function(){
38850 var s = this.selNode || this.lastSelNode;
38854 if(s.firstChild && s.isExpanded()){
38855 return this.select(s.firstChild);
38856 }else if(s.nextSibling){
38857 return this.select(s.nextSibling);
38858 }else if(s.parentNode){
38860 s.parentNode.bubble(function(){
38861 if(this.nextSibling){
38862 newS = this.getOwnerTree().selModel.select(this.nextSibling);
38871 onKeyDown : function(e){
38872 var s = this.selNode || this.lastSelNode;
38873 // undesirable, but required
38878 var k = e.getKey();
38886 this.selectPrevious();
38889 e.preventDefault();
38890 if(s.hasChildNodes()){
38891 if(!s.isExpanded()){
38893 }else if(s.firstChild){
38894 this.select(s.firstChild, e);
38899 e.preventDefault();
38900 if(s.hasChildNodes() && s.isExpanded()){
38902 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
38903 this.select(s.parentNode, e);
38911 * @class Roo.tree.MultiSelectionModel
38912 * @extends Roo.util.Observable
38913 * Multi selection for a TreePanel.
38914 * @param {Object} cfg Configuration
38916 Roo.tree.MultiSelectionModel = function(){
38917 this.selNodes = [];
38921 * @event selectionchange
38922 * Fires when the selected nodes change
38923 * @param {MultiSelectionModel} this
38924 * @param {Array} nodes Array of the selected nodes
38926 "selectionchange" : true
38928 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
38932 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
38933 init : function(tree){
38935 tree.getTreeEl().on("keydown", this.onKeyDown, this);
38936 tree.on("click", this.onNodeClick, this);
38939 onNodeClick : function(node, e){
38940 this.select(node, e, e.ctrlKey);
38945 * @param {TreeNode} node The node to select
38946 * @param {EventObject} e (optional) An event associated with the selection
38947 * @param {Boolean} keepExisting True to retain existing selections
38948 * @return {TreeNode} The selected node
38950 select : function(node, e, keepExisting){
38951 if(keepExisting !== true){
38952 this.clearSelections(true);
38954 if(this.isSelected(node)){
38955 this.lastSelNode = node;
38958 this.selNodes.push(node);
38959 this.selMap[node.id] = node;
38960 this.lastSelNode = node;
38961 node.ui.onSelectedChange(true);
38962 this.fireEvent("selectionchange", this, this.selNodes);
38968 * @param {TreeNode} node The node to unselect
38970 unselect : function(node){
38971 if(this.selMap[node.id]){
38972 node.ui.onSelectedChange(false);
38973 var sn = this.selNodes;
38976 index = sn.indexOf(node);
38978 for(var i = 0, len = sn.length; i < len; i++){
38986 this.selNodes.splice(index, 1);
38988 delete this.selMap[node.id];
38989 this.fireEvent("selectionchange", this, this.selNodes);
38994 * Clear all selections
38996 clearSelections : function(suppressEvent){
38997 var sn = this.selNodes;
38999 for(var i = 0, len = sn.length; i < len; i++){
39000 sn[i].ui.onSelectedChange(false);
39002 this.selNodes = [];
39004 if(suppressEvent !== true){
39005 this.fireEvent("selectionchange", this, this.selNodes);
39011 * Returns true if the node is selected
39012 * @param {TreeNode} node The node to check
39013 * @return {Boolean}
39015 isSelected : function(node){
39016 return this.selMap[node.id] ? true : false;
39020 * Returns an array of the selected nodes
39023 getSelectedNodes : function(){
39024 return this.selNodes;
39027 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
39029 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
39031 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
39034 * Ext JS Library 1.1.1
39035 * Copyright(c) 2006-2007, Ext JS, LLC.
39037 * Originally Released Under LGPL - original licence link has changed is not relivant.
39040 * <script type="text/javascript">
39044 * @class Roo.tree.TreeNode
39045 * @extends Roo.data.Node
39046 * @cfg {String} text The text for this node
39047 * @cfg {Boolean} expanded true to start the node expanded
39048 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
39049 * @cfg {Boolean} allowDrop false if this node cannot be drop on
39050 * @cfg {Boolean} disabled true to start the node disabled
39051 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
39052 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
39053 * @cfg {String} cls A css class to be added to the node
39054 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
39055 * @cfg {String} href URL of the link used for the node (defaults to #)
39056 * @cfg {String} hrefTarget target frame for the link
39057 * @cfg {String} qtip An Ext QuickTip for the node
39058 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
39059 * @cfg {Boolean} singleClickExpand True for single click expand on this node
39060 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
39061 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
39062 * (defaults to undefined with no checkbox rendered)
39064 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
39066 Roo.tree.TreeNode = function(attributes){
39067 attributes = attributes || {};
39068 if(typeof attributes == "string"){
39069 attributes = {text: attributes};
39071 this.childrenRendered = false;
39072 this.rendered = false;
39073 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
39074 this.expanded = attributes.expanded === true;
39075 this.isTarget = attributes.isTarget !== false;
39076 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
39077 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
39080 * Read-only. The text for this node. To change it use setText().
39083 this.text = attributes.text;
39085 * True if this node is disabled.
39088 this.disabled = attributes.disabled === true;
39092 * @event textchange
39093 * Fires when the text for this node is changed
39094 * @param {Node} this This node
39095 * @param {String} text The new text
39096 * @param {String} oldText The old text
39098 "textchange" : true,
39100 * @event beforeexpand
39101 * Fires before this node is expanded, return false to cancel.
39102 * @param {Node} this This node
39103 * @param {Boolean} deep
39104 * @param {Boolean} anim
39106 "beforeexpand" : true,
39108 * @event beforecollapse
39109 * Fires before this node is collapsed, return false to cancel.
39110 * @param {Node} this This node
39111 * @param {Boolean} deep
39112 * @param {Boolean} anim
39114 "beforecollapse" : true,
39117 * Fires when this node is expanded
39118 * @param {Node} this This node
39122 * @event disabledchange
39123 * Fires when the disabled status of this node changes
39124 * @param {Node} this This node
39125 * @param {Boolean} disabled
39127 "disabledchange" : true,
39130 * Fires when this node is collapsed
39131 * @param {Node} this This node
39135 * @event beforeclick
39136 * Fires before click processing. Return false to cancel the default action.
39137 * @param {Node} this This node
39138 * @param {Roo.EventObject} e The event object
39140 "beforeclick":true,
39142 * @event checkchange
39143 * Fires when a node with a checkbox's checked property changes
39144 * @param {Node} this This node
39145 * @param {Boolean} checked
39147 "checkchange":true,
39150 * Fires when this node is clicked
39151 * @param {Node} this This node
39152 * @param {Roo.EventObject} e The event object
39157 * Fires when this node is double clicked
39158 * @param {Node} this This node
39159 * @param {Roo.EventObject} e The event object
39163 * @event contextmenu
39164 * Fires when this node is right clicked
39165 * @param {Node} this This node
39166 * @param {Roo.EventObject} e The event object
39168 "contextmenu":true,
39170 * @event beforechildrenrendered
39171 * Fires right before the child nodes for this node are rendered
39172 * @param {Node} this This node
39174 "beforechildrenrendered":true
39177 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
39180 * Read-only. The UI for this node
39183 this.ui = new uiClass(this);
39185 // finally support items[]
39186 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
39191 Roo.each(this.attributes.items, function(c) {
39192 this.appendChild(Roo.factory(c,Roo.Tree));
39194 delete this.attributes.items;
39199 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
39200 preventHScroll: true,
39202 * Returns true if this node is expanded
39203 * @return {Boolean}
39205 isExpanded : function(){
39206 return this.expanded;
39210 * Returns the UI object for this node
39211 * @return {TreeNodeUI}
39213 getUI : function(){
39217 // private override
39218 setFirstChild : function(node){
39219 var of = this.firstChild;
39220 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
39221 if(this.childrenRendered && of && node != of){
39222 of.renderIndent(true, true);
39225 this.renderIndent(true, true);
39229 // private override
39230 setLastChild : function(node){
39231 var ol = this.lastChild;
39232 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
39233 if(this.childrenRendered && ol && node != ol){
39234 ol.renderIndent(true, true);
39237 this.renderIndent(true, true);
39241 // these methods are overridden to provide lazy rendering support
39242 // private override
39243 appendChild : function()
39245 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
39246 if(node && this.childrenRendered){
39249 this.ui.updateExpandIcon();
39253 // private override
39254 removeChild : function(node){
39255 this.ownerTree.getSelectionModel().unselect(node);
39256 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
39257 // if it's been rendered remove dom node
39258 if(this.childrenRendered){
39261 if(this.childNodes.length < 1){
39262 this.collapse(false, false);
39264 this.ui.updateExpandIcon();
39266 if(!this.firstChild) {
39267 this.childrenRendered = false;
39272 // private override
39273 insertBefore : function(node, refNode){
39274 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
39275 if(newNode && refNode && this.childrenRendered){
39278 this.ui.updateExpandIcon();
39283 * Sets the text for this node
39284 * @param {String} text
39286 setText : function(text){
39287 var oldText = this.text;
39289 this.attributes.text = text;
39290 if(this.rendered){ // event without subscribing
39291 this.ui.onTextChange(this, text, oldText);
39293 this.fireEvent("textchange", this, text, oldText);
39297 * Triggers selection of this node
39299 select : function(){
39300 this.getOwnerTree().getSelectionModel().select(this);
39304 * Triggers deselection of this node
39306 unselect : function(){
39307 this.getOwnerTree().getSelectionModel().unselect(this);
39311 * Returns true if this node is selected
39312 * @return {Boolean}
39314 isSelected : function(){
39315 return this.getOwnerTree().getSelectionModel().isSelected(this);
39319 * Expand this node.
39320 * @param {Boolean} deep (optional) True to expand all children as well
39321 * @param {Boolean} anim (optional) false to cancel the default animation
39322 * @param {Function} callback (optional) A callback to be called when
39323 * expanding this node completes (does not wait for deep expand to complete).
39324 * Called with 1 parameter, this node.
39326 expand : function(deep, anim, callback){
39327 if(!this.expanded){
39328 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
39331 if(!this.childrenRendered){
39332 this.renderChildren();
39334 this.expanded = true;
39335 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
39336 this.ui.animExpand(function(){
39337 this.fireEvent("expand", this);
39338 if(typeof callback == "function"){
39342 this.expandChildNodes(true);
39344 }.createDelegate(this));
39348 this.fireEvent("expand", this);
39349 if(typeof callback == "function"){
39354 if(typeof callback == "function"){
39359 this.expandChildNodes(true);
39363 isHiddenRoot : function(){
39364 return this.isRoot && !this.getOwnerTree().rootVisible;
39368 * Collapse this node.
39369 * @param {Boolean} deep (optional) True to collapse all children as well
39370 * @param {Boolean} anim (optional) false to cancel the default animation
39372 collapse : function(deep, anim){
39373 if(this.expanded && !this.isHiddenRoot()){
39374 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
39377 this.expanded = false;
39378 if((this.getOwnerTree().animate && anim !== false) || anim){
39379 this.ui.animCollapse(function(){
39380 this.fireEvent("collapse", this);
39382 this.collapseChildNodes(true);
39384 }.createDelegate(this));
39387 this.ui.collapse();
39388 this.fireEvent("collapse", this);
39392 var cs = this.childNodes;
39393 for(var i = 0, len = cs.length; i < len; i++) {
39394 cs[i].collapse(true, false);
39400 delayedExpand : function(delay){
39401 if(!this.expandProcId){
39402 this.expandProcId = this.expand.defer(delay, this);
39407 cancelExpand : function(){
39408 if(this.expandProcId){
39409 clearTimeout(this.expandProcId);
39411 this.expandProcId = false;
39415 * Toggles expanded/collapsed state of the node
39417 toggle : function(){
39426 * Ensures all parent nodes are expanded
39428 ensureVisible : function(callback){
39429 var tree = this.getOwnerTree();
39430 tree.expandPath(this.parentNode.getPath(), false, function(){
39431 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
39432 Roo.callback(callback);
39433 }.createDelegate(this));
39437 * Expand all child nodes
39438 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
39440 expandChildNodes : function(deep){
39441 var cs = this.childNodes;
39442 for(var i = 0, len = cs.length; i < len; i++) {
39443 cs[i].expand(deep);
39448 * Collapse all child nodes
39449 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
39451 collapseChildNodes : function(deep){
39452 var cs = this.childNodes;
39453 for(var i = 0, len = cs.length; i < len; i++) {
39454 cs[i].collapse(deep);
39459 * Disables this node
39461 disable : function(){
39462 this.disabled = true;
39464 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
39465 this.ui.onDisableChange(this, true);
39467 this.fireEvent("disabledchange", this, true);
39471 * Enables this node
39473 enable : function(){
39474 this.disabled = false;
39475 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
39476 this.ui.onDisableChange(this, false);
39478 this.fireEvent("disabledchange", this, false);
39482 renderChildren : function(suppressEvent){
39483 if(suppressEvent !== false){
39484 this.fireEvent("beforechildrenrendered", this);
39486 var cs = this.childNodes;
39487 for(var i = 0, len = cs.length; i < len; i++){
39488 cs[i].render(true);
39490 this.childrenRendered = true;
39494 sort : function(fn, scope){
39495 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
39496 if(this.childrenRendered){
39497 var cs = this.childNodes;
39498 for(var i = 0, len = cs.length; i < len; i++){
39499 cs[i].render(true);
39505 render : function(bulkRender){
39506 this.ui.render(bulkRender);
39507 if(!this.rendered){
39508 this.rendered = true;
39510 this.expanded = false;
39511 this.expand(false, false);
39517 renderIndent : function(deep, refresh){
39519 this.ui.childIndent = null;
39521 this.ui.renderIndent();
39522 if(deep === true && this.childrenRendered){
39523 var cs = this.childNodes;
39524 for(var i = 0, len = cs.length; i < len; i++){
39525 cs[i].renderIndent(true, refresh);
39531 * Ext JS Library 1.1.1
39532 * Copyright(c) 2006-2007, Ext JS, LLC.
39534 * Originally Released Under LGPL - original licence link has changed is not relivant.
39537 * <script type="text/javascript">
39541 * @class Roo.tree.AsyncTreeNode
39542 * @extends Roo.tree.TreeNode
39543 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
39545 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
39547 Roo.tree.AsyncTreeNode = function(config){
39548 this.loaded = false;
39549 this.loading = false;
39550 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
39552 * @event beforeload
39553 * Fires before this node is loaded, return false to cancel
39554 * @param {Node} this This node
39556 this.addEvents({'beforeload':true, 'load': true});
39559 * Fires when this node is loaded
39560 * @param {Node} this This node
39563 * The loader used by this node (defaults to using the tree's defined loader)
39568 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
39569 expand : function(deep, anim, callback){
39570 if(this.loading){ // if an async load is already running, waiting til it's done
39572 var f = function(){
39573 if(!this.loading){ // done loading
39574 clearInterval(timer);
39575 this.expand(deep, anim, callback);
39577 }.createDelegate(this);
39578 timer = setInterval(f, 200);
39582 if(this.fireEvent("beforeload", this) === false){
39585 this.loading = true;
39586 this.ui.beforeLoad(this);
39587 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
39589 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
39593 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
39597 * Returns true if this node is currently loading
39598 * @return {Boolean}
39600 isLoading : function(){
39601 return this.loading;
39604 loadComplete : function(deep, anim, callback){
39605 this.loading = false;
39606 this.loaded = true;
39607 this.ui.afterLoad(this);
39608 this.fireEvent("load", this);
39609 this.expand(deep, anim, callback);
39613 * Returns true if this node has been loaded
39614 * @return {Boolean}
39616 isLoaded : function(){
39617 return this.loaded;
39620 hasChildNodes : function(){
39621 if(!this.isLeaf() && !this.loaded){
39624 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
39629 * Trigger a reload for this node
39630 * @param {Function} callback
39632 reload : function(callback){
39633 this.collapse(false, false);
39634 while(this.firstChild){
39635 this.removeChild(this.firstChild);
39637 this.childrenRendered = false;
39638 this.loaded = false;
39639 if(this.isHiddenRoot()){
39640 this.expanded = false;
39642 this.expand(false, false, callback);
39646 * Ext JS Library 1.1.1
39647 * Copyright(c) 2006-2007, Ext JS, LLC.
39649 * Originally Released Under LGPL - original licence link has changed is not relivant.
39652 * <script type="text/javascript">
39656 * @class Roo.tree.TreeNodeUI
39658 * @param {Object} node The node to render
39659 * The TreeNode UI implementation is separate from the
39660 * tree implementation. Unless you are customizing the tree UI,
39661 * you should never have to use this directly.
39663 Roo.tree.TreeNodeUI = function(node){
39665 this.rendered = false;
39666 this.animating = false;
39667 this.emptyIcon = Roo.BLANK_IMAGE_URL;
39670 Roo.tree.TreeNodeUI.prototype = {
39671 removeChild : function(node){
39673 this.ctNode.removeChild(node.ui.getEl());
39677 beforeLoad : function(){
39678 this.addClass("x-tree-node-loading");
39681 afterLoad : function(){
39682 this.removeClass("x-tree-node-loading");
39685 onTextChange : function(node, text, oldText){
39687 this.textNode.innerHTML = text;
39691 onDisableChange : function(node, state){
39692 this.disabled = state;
39694 this.addClass("x-tree-node-disabled");
39696 this.removeClass("x-tree-node-disabled");
39700 onSelectedChange : function(state){
39703 this.addClass("x-tree-selected");
39706 this.removeClass("x-tree-selected");
39710 onMove : function(tree, node, oldParent, newParent, index, refNode){
39711 this.childIndent = null;
39713 var targetNode = newParent.ui.getContainer();
39714 if(!targetNode){//target not rendered
39715 this.holder = document.createElement("div");
39716 this.holder.appendChild(this.wrap);
39719 var insertBefore = refNode ? refNode.ui.getEl() : null;
39721 targetNode.insertBefore(this.wrap, insertBefore);
39723 targetNode.appendChild(this.wrap);
39725 this.node.renderIndent(true);
39729 addClass : function(cls){
39731 Roo.fly(this.elNode).addClass(cls);
39735 removeClass : function(cls){
39737 Roo.fly(this.elNode).removeClass(cls);
39741 remove : function(){
39743 this.holder = document.createElement("div");
39744 this.holder.appendChild(this.wrap);
39748 fireEvent : function(){
39749 return this.node.fireEvent.apply(this.node, arguments);
39752 initEvents : function(){
39753 this.node.on("move", this.onMove, this);
39754 var E = Roo.EventManager;
39755 var a = this.anchor;
39757 var el = Roo.fly(a, '_treeui');
39759 if(Roo.isOpera){ // opera render bug ignores the CSS
39760 el.setStyle("text-decoration", "none");
39763 el.on("click", this.onClick, this);
39764 el.on("dblclick", this.onDblClick, this);
39767 Roo.EventManager.on(this.checkbox,
39768 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
39771 el.on("contextmenu", this.onContextMenu, this);
39773 var icon = Roo.fly(this.iconNode);
39774 icon.on("click", this.onClick, this);
39775 icon.on("dblclick", this.onDblClick, this);
39776 icon.on("contextmenu", this.onContextMenu, this);
39777 E.on(this.ecNode, "click", this.ecClick, this, true);
39779 if(this.node.disabled){
39780 this.addClass("x-tree-node-disabled");
39782 if(this.node.hidden){
39783 this.addClass("x-tree-node-disabled");
39785 var ot = this.node.getOwnerTree();
39786 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
39787 if(dd && (!this.node.isRoot || ot.rootVisible)){
39788 Roo.dd.Registry.register(this.elNode, {
39790 handles: this.getDDHandles(),
39796 getDDHandles : function(){
39797 return [this.iconNode, this.textNode];
39802 this.wrap.style.display = "none";
39808 this.wrap.style.display = "";
39812 onContextMenu : function(e){
39813 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
39814 e.preventDefault();
39816 this.fireEvent("contextmenu", this.node, e);
39820 onClick : function(e){
39825 if(this.fireEvent("beforeclick", this.node, e) !== false){
39826 if(!this.disabled && this.node.attributes.href){
39827 this.fireEvent("click", this.node, e);
39830 e.preventDefault();
39835 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
39836 this.node.toggle();
39839 this.fireEvent("click", this.node, e);
39845 onDblClick : function(e){
39846 e.preventDefault();
39851 this.toggleCheck();
39853 if(!this.animating && this.node.hasChildNodes()){
39854 this.node.toggle();
39856 this.fireEvent("dblclick", this.node, e);
39859 onCheckChange : function(){
39860 var checked = this.checkbox.checked;
39861 this.node.attributes.checked = checked;
39862 this.fireEvent('checkchange', this.node, checked);
39865 ecClick : function(e){
39866 if(!this.animating && this.node.hasChildNodes()){
39867 this.node.toggle();
39871 startDrop : function(){
39872 this.dropping = true;
39875 // delayed drop so the click event doesn't get fired on a drop
39876 endDrop : function(){
39877 setTimeout(function(){
39878 this.dropping = false;
39879 }.createDelegate(this), 50);
39882 expand : function(){
39883 this.updateExpandIcon();
39884 this.ctNode.style.display = "";
39887 focus : function(){
39888 if(!this.node.preventHScroll){
39889 try{this.anchor.focus();
39891 }else if(!Roo.isIE){
39893 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
39894 var l = noscroll.scrollLeft;
39895 this.anchor.focus();
39896 noscroll.scrollLeft = l;
39901 toggleCheck : function(value){
39902 var cb = this.checkbox;
39904 cb.checked = (value === undefined ? !cb.checked : value);
39910 this.anchor.blur();
39914 animExpand : function(callback){
39915 var ct = Roo.get(this.ctNode);
39917 if(!this.node.hasChildNodes()){
39918 this.updateExpandIcon();
39919 this.ctNode.style.display = "";
39920 Roo.callback(callback);
39923 this.animating = true;
39924 this.updateExpandIcon();
39927 callback : function(){
39928 this.animating = false;
39929 Roo.callback(callback);
39932 duration: this.node.ownerTree.duration || .25
39936 highlight : function(){
39937 var tree = this.node.getOwnerTree();
39938 Roo.fly(this.wrap).highlight(
39939 tree.hlColor || "C3DAF9",
39940 {endColor: tree.hlBaseColor}
39944 collapse : function(){
39945 this.updateExpandIcon();
39946 this.ctNode.style.display = "none";
39949 animCollapse : function(callback){
39950 var ct = Roo.get(this.ctNode);
39951 ct.enableDisplayMode('block');
39954 this.animating = true;
39955 this.updateExpandIcon();
39958 callback : function(){
39959 this.animating = false;
39960 Roo.callback(callback);
39963 duration: this.node.ownerTree.duration || .25
39967 getContainer : function(){
39968 return this.ctNode;
39971 getEl : function(){
39975 appendDDGhost : function(ghostNode){
39976 ghostNode.appendChild(this.elNode.cloneNode(true));
39979 getDDRepairXY : function(){
39980 return Roo.lib.Dom.getXY(this.iconNode);
39983 onRender : function(){
39987 render : function(bulkRender){
39988 var n = this.node, a = n.attributes;
39989 var targetNode = n.parentNode ?
39990 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
39992 if(!this.rendered){
39993 this.rendered = true;
39995 this.renderElements(n, a, targetNode, bulkRender);
39998 if(this.textNode.setAttributeNS){
39999 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
40001 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
40004 this.textNode.setAttribute("ext:qtip", a.qtip);
40006 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
40009 }else if(a.qtipCfg){
40010 a.qtipCfg.target = Roo.id(this.textNode);
40011 Roo.QuickTips.register(a.qtipCfg);
40014 if(!this.node.expanded){
40015 this.updateExpandIcon();
40018 if(bulkRender === true) {
40019 targetNode.appendChild(this.wrap);
40024 renderElements : function(n, a, targetNode, bulkRender)
40026 // add some indent caching, this helps performance when rendering a large tree
40027 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
40028 var t = n.getOwnerTree();
40029 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
40030 if (typeof(n.attributes.html) != 'undefined') {
40031 txt = n.attributes.html;
40033 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
40034 var cb = typeof a.checked == 'boolean';
40035 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
40036 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
40037 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
40038 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
40039 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
40040 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
40041 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
40042 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
40043 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
40044 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
40047 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
40048 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
40049 n.nextSibling.ui.getEl(), buf.join(""));
40051 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
40054 this.elNode = this.wrap.childNodes[0];
40055 this.ctNode = this.wrap.childNodes[1];
40056 var cs = this.elNode.childNodes;
40057 this.indentNode = cs[0];
40058 this.ecNode = cs[1];
40059 this.iconNode = cs[2];
40062 this.checkbox = cs[3];
40065 this.anchor = cs[index];
40066 this.textNode = cs[index].firstChild;
40069 getAnchor : function(){
40070 return this.anchor;
40073 getTextEl : function(){
40074 return this.textNode;
40077 getIconEl : function(){
40078 return this.iconNode;
40081 isChecked : function(){
40082 return this.checkbox ? this.checkbox.checked : false;
40085 updateExpandIcon : function(){
40087 var n = this.node, c1, c2;
40088 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
40089 var hasChild = n.hasChildNodes();
40093 c1 = "x-tree-node-collapsed";
40094 c2 = "x-tree-node-expanded";
40097 c1 = "x-tree-node-expanded";
40098 c2 = "x-tree-node-collapsed";
40101 this.removeClass("x-tree-node-leaf");
40102 this.wasLeaf = false;
40104 if(this.c1 != c1 || this.c2 != c2){
40105 Roo.fly(this.elNode).replaceClass(c1, c2);
40106 this.c1 = c1; this.c2 = c2;
40109 // this changes non-leafs into leafs if they have no children.
40110 // it's not very rational behaviour..
40112 if(!this.wasLeaf && this.node.leaf){
40113 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
40116 this.wasLeaf = true;
40119 var ecc = "x-tree-ec-icon "+cls;
40120 if(this.ecc != ecc){
40121 this.ecNode.className = ecc;
40127 getChildIndent : function(){
40128 if(!this.childIndent){
40132 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
40134 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
40136 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
40141 this.childIndent = buf.join("");
40143 return this.childIndent;
40146 renderIndent : function(){
40149 var p = this.node.parentNode;
40151 indent = p.ui.getChildIndent();
40153 if(this.indentMarkup != indent){ // don't rerender if not required
40154 this.indentNode.innerHTML = indent;
40155 this.indentMarkup = indent;
40157 this.updateExpandIcon();
40162 Roo.tree.RootTreeNodeUI = function(){
40163 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
40165 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
40166 render : function(){
40167 if(!this.rendered){
40168 var targetNode = this.node.ownerTree.innerCt.dom;
40169 this.node.expanded = true;
40170 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
40171 this.wrap = this.ctNode = targetNode.firstChild;
40174 collapse : function(){
40176 expand : function(){
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">
40189 * @class Roo.tree.TreeLoader
40190 * @extends Roo.util.Observable
40191 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
40192 * nodes from a specified URL. The response must be a javascript Array definition
40193 * who's elements are node definition objects. eg:
40198 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
40199 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
40206 * The old style respose with just an array is still supported, but not recommended.
40209 * A server request is sent, and child nodes are loaded only when a node is expanded.
40210 * The loading node's id is passed to the server under the parameter name "node" to
40211 * enable the server to produce the correct child nodes.
40213 * To pass extra parameters, an event handler may be attached to the "beforeload"
40214 * event, and the parameters specified in the TreeLoader's baseParams property:
40216 myTreeLoader.on("beforeload", function(treeLoader, node) {
40217 this.baseParams.category = node.attributes.category;
40220 * This would pass an HTTP parameter called "category" to the server containing
40221 * the value of the Node's "category" attribute.
40223 * Creates a new Treeloader.
40224 * @param {Object} config A config object containing config properties.
40226 Roo.tree.TreeLoader = function(config){
40227 this.baseParams = {};
40228 this.requestMethod = "POST";
40229 Roo.apply(this, config);
40234 * @event beforeload
40235 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
40236 * @param {Object} This TreeLoader object.
40237 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
40238 * @param {Object} callback The callback function specified in the {@link #load} call.
40243 * Fires when the node has been successfuly loaded.
40244 * @param {Object} This TreeLoader object.
40245 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
40246 * @param {Object} response The response object containing the data from the server.
40250 * @event loadexception
40251 * Fires if the network request failed.
40252 * @param {Object} This TreeLoader object.
40253 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
40254 * @param {Object} response The response object containing the data from the server.
40256 loadexception : true,
40259 * Fires before a node is created, enabling you to return custom Node types
40260 * @param {Object} This TreeLoader object.
40261 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
40266 Roo.tree.TreeLoader.superclass.constructor.call(this);
40269 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
40271 * @cfg {String} dataUrl The URL from which to request a Json string which
40272 * specifies an array of node definition object representing the child nodes
40276 * @cfg {String} requestMethod either GET or POST
40277 * defaults to POST (due to BC)
40281 * @cfg {Object} baseParams (optional) An object containing properties which
40282 * specify HTTP parameters to be passed to each request for child nodes.
40285 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
40286 * created by this loader. If the attributes sent by the server have an attribute in this object,
40287 * they take priority.
40290 * @cfg {Object} uiProviders (optional) An object containing properties which
40292 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
40293 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
40294 * <i>uiProvider</i> attribute of a returned child node is a string rather
40295 * than a reference to a TreeNodeUI implementation, this that string value
40296 * is used as a property name in the uiProviders object. You can define the provider named
40297 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
40302 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
40303 * child nodes before loading.
40305 clearOnLoad : true,
40308 * @cfg {String} root (optional) Default to false. Use this to read data from an object
40309 * property on loading, rather than expecting an array. (eg. more compatible to a standard
40310 * Grid query { data : [ .....] }
40315 * @cfg {String} queryParam (optional)
40316 * Name of the query as it will be passed on the querystring (defaults to 'node')
40317 * eg. the request will be ?node=[id]
40324 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
40325 * This is called automatically when a node is expanded, but may be used to reload
40326 * a node (or append new children if the {@link #clearOnLoad} option is false.)
40327 * @param {Roo.tree.TreeNode} node
40328 * @param {Function} callback
40330 load : function(node, callback){
40331 if(this.clearOnLoad){
40332 while(node.firstChild){
40333 node.removeChild(node.firstChild);
40336 if(node.attributes.children){ // preloaded json children
40337 var cs = node.attributes.children;
40338 for(var i = 0, len = cs.length; i < len; i++){
40339 node.appendChild(this.createNode(cs[i]));
40341 if(typeof callback == "function"){
40344 }else if(this.dataUrl){
40345 this.requestData(node, callback);
40349 getParams: function(node){
40350 var buf = [], bp = this.baseParams;
40351 for(var key in bp){
40352 if(typeof bp[key] != "function"){
40353 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
40356 var n = this.queryParam === false ? 'node' : this.queryParam;
40357 buf.push(n + "=", encodeURIComponent(node.id));
40358 return buf.join("");
40361 requestData : function(node, callback){
40362 if(this.fireEvent("beforeload", this, node, callback) !== false){
40363 this.transId = Roo.Ajax.request({
40364 method:this.requestMethod,
40365 url: this.dataUrl||this.url,
40366 success: this.handleResponse,
40367 failure: this.handleFailure,
40369 argument: {callback: callback, node: node},
40370 params: this.getParams(node)
40373 // if the load is cancelled, make sure we notify
40374 // the node that we are done
40375 if(typeof callback == "function"){
40381 isLoading : function(){
40382 return this.transId ? true : false;
40385 abort : function(){
40386 if(this.isLoading()){
40387 Roo.Ajax.abort(this.transId);
40392 createNode : function(attr)
40394 // apply baseAttrs, nice idea Corey!
40395 if(this.baseAttrs){
40396 Roo.applyIf(attr, this.baseAttrs);
40398 if(this.applyLoader !== false){
40399 attr.loader = this;
40401 // uiProvider = depreciated..
40403 if(typeof(attr.uiProvider) == 'string'){
40404 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
40405 /** eval:var:attr */ eval(attr.uiProvider);
40407 if(typeof(this.uiProviders['default']) != 'undefined') {
40408 attr.uiProvider = this.uiProviders['default'];
40411 this.fireEvent('create', this, attr);
40413 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
40415 new Roo.tree.TreeNode(attr) :
40416 new Roo.tree.AsyncTreeNode(attr));
40419 processResponse : function(response, node, callback)
40421 var json = response.responseText;
40424 var o = Roo.decode(json);
40426 if (this.root === false && typeof(o.success) != undefined) {
40427 this.root = 'data'; // the default behaviour for list like data..
40430 if (this.root !== false && !o.success) {
40431 // it's a failure condition.
40432 var a = response.argument;
40433 this.fireEvent("loadexception", this, a.node, response);
40434 Roo.log("Load failed - should have a handler really");
40440 if (this.root !== false) {
40444 for(var i = 0, len = o.length; i < len; i++){
40445 var n = this.createNode(o[i]);
40447 node.appendChild(n);
40450 if(typeof callback == "function"){
40451 callback(this, node);
40454 this.handleFailure(response);
40458 handleResponse : function(response){
40459 this.transId = false;
40460 var a = response.argument;
40461 this.processResponse(response, a.node, a.callback);
40462 this.fireEvent("load", this, a.node, response);
40465 handleFailure : function(response)
40467 // should handle failure better..
40468 this.transId = false;
40469 var a = response.argument;
40470 this.fireEvent("loadexception", this, a.node, response);
40471 if(typeof a.callback == "function"){
40472 a.callback(this, a.node);
40477 * Ext JS Library 1.1.1
40478 * Copyright(c) 2006-2007, Ext JS, LLC.
40480 * Originally Released Under LGPL - original licence link has changed is not relivant.
40483 * <script type="text/javascript">
40487 * @class Roo.tree.TreeFilter
40488 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
40489 * @param {TreePanel} tree
40490 * @param {Object} config (optional)
40492 Roo.tree.TreeFilter = function(tree, config){
40494 this.filtered = {};
40495 Roo.apply(this, config);
40498 Roo.tree.TreeFilter.prototype = {
40505 * Filter the data by a specific attribute.
40506 * @param {String/RegExp} value Either string that the attribute value
40507 * should start with or a RegExp to test against the attribute
40508 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
40509 * @param {TreeNode} startNode (optional) The node to start the filter at.
40511 filter : function(value, attr, startNode){
40512 attr = attr || "text";
40514 if(typeof value == "string"){
40515 var vlen = value.length;
40516 // auto clear empty filter
40517 if(vlen == 0 && this.clearBlank){
40521 value = value.toLowerCase();
40523 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
40525 }else if(value.exec){ // regex?
40527 return value.test(n.attributes[attr]);
40530 throw 'Illegal filter type, must be string or regex';
40532 this.filterBy(f, null, startNode);
40536 * Filter by a function. The passed function will be called with each
40537 * node in the tree (or from the startNode). If the function returns true, the node is kept
40538 * otherwise it is filtered. If a node is filtered, its children are also filtered.
40539 * @param {Function} fn The filter function
40540 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
40542 filterBy : function(fn, scope, startNode){
40543 startNode = startNode || this.tree.root;
40544 if(this.autoClear){
40547 var af = this.filtered, rv = this.reverse;
40548 var f = function(n){
40549 if(n == startNode){
40555 var m = fn.call(scope || n, n);
40563 startNode.cascade(f);
40566 if(typeof id != "function"){
40568 if(n && n.parentNode){
40569 n.parentNode.removeChild(n);
40577 * Clears the current filter. Note: with the "remove" option
40578 * set a filter cannot be cleared.
40580 clear : function(){
40582 var af = this.filtered;
40584 if(typeof id != "function"){
40591 this.filtered = {};
40596 * Ext JS Library 1.1.1
40597 * Copyright(c) 2006-2007, Ext JS, LLC.
40599 * Originally Released Under LGPL - original licence link has changed is not relivant.
40602 * <script type="text/javascript">
40607 * @class Roo.tree.TreeSorter
40608 * Provides sorting of nodes in a TreePanel
40610 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
40611 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
40612 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
40613 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
40614 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
40615 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
40617 * @param {TreePanel} tree
40618 * @param {Object} config
40620 Roo.tree.TreeSorter = function(tree, config){
40621 Roo.apply(this, config);
40622 tree.on("beforechildrenrendered", this.doSort, this);
40623 tree.on("append", this.updateSort, this);
40624 tree.on("insert", this.updateSort, this);
40626 var dsc = this.dir && this.dir.toLowerCase() == "desc";
40627 var p = this.property || "text";
40628 var sortType = this.sortType;
40629 var fs = this.folderSort;
40630 var cs = this.caseSensitive === true;
40631 var leafAttr = this.leafAttr || 'leaf';
40633 this.sortFn = function(n1, n2){
40635 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
40638 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
40642 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
40643 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
40645 return dsc ? +1 : -1;
40647 return dsc ? -1 : +1;
40654 Roo.tree.TreeSorter.prototype = {
40655 doSort : function(node){
40656 node.sort(this.sortFn);
40659 compareNodes : function(n1, n2){
40660 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
40663 updateSort : function(tree, node){
40664 if(node.childrenRendered){
40665 this.doSort.defer(1, this, [node]);
40670 * Ext JS Library 1.1.1
40671 * Copyright(c) 2006-2007, Ext JS, LLC.
40673 * Originally Released Under LGPL - original licence link has changed is not relivant.
40676 * <script type="text/javascript">
40679 if(Roo.dd.DropZone){
40681 Roo.tree.TreeDropZone = function(tree, config){
40682 this.allowParentInsert = false;
40683 this.allowContainerDrop = false;
40684 this.appendOnly = false;
40685 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
40687 this.lastInsertClass = "x-tree-no-status";
40688 this.dragOverData = {};
40691 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
40692 ddGroup : "TreeDD",
40695 expandDelay : 1000,
40697 expandNode : function(node){
40698 if(node.hasChildNodes() && !node.isExpanded()){
40699 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
40703 queueExpand : function(node){
40704 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
40707 cancelExpand : function(){
40708 if(this.expandProcId){
40709 clearTimeout(this.expandProcId);
40710 this.expandProcId = false;
40714 isValidDropPoint : function(n, pt, dd, e, data){
40715 if(!n || !data){ return false; }
40716 var targetNode = n.node;
40717 var dropNode = data.node;
40718 // default drop rules
40719 if(!(targetNode && targetNode.isTarget && pt)){
40722 if(pt == "append" && targetNode.allowChildren === false){
40725 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
40728 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
40731 // reuse the object
40732 var overEvent = this.dragOverData;
40733 overEvent.tree = this.tree;
40734 overEvent.target = targetNode;
40735 overEvent.data = data;
40736 overEvent.point = pt;
40737 overEvent.source = dd;
40738 overEvent.rawEvent = e;
40739 overEvent.dropNode = dropNode;
40740 overEvent.cancel = false;
40741 var result = this.tree.fireEvent("nodedragover", overEvent);
40742 return overEvent.cancel === false && result !== false;
40745 getDropPoint : function(e, n, dd)
40749 return tn.allowChildren !== false ? "append" : false; // always append for root
40751 var dragEl = n.ddel;
40752 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
40753 var y = Roo.lib.Event.getPageY(e);
40754 //var noAppend = tn.allowChildren === false || tn.isLeaf();
40756 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
40757 var noAppend = tn.allowChildren === false;
40758 if(this.appendOnly || tn.parentNode.allowChildren === false){
40759 return noAppend ? false : "append";
40761 var noBelow = false;
40762 if(!this.allowParentInsert){
40763 noBelow = tn.hasChildNodes() && tn.isExpanded();
40765 var q = (b - t) / (noAppend ? 2 : 3);
40766 if(y >= t && y < (t + q)){
40768 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
40775 onNodeEnter : function(n, dd, e, data)
40777 this.cancelExpand();
40780 onNodeOver : function(n, dd, e, data)
40783 var pt = this.getDropPoint(e, n, dd);
40786 // auto node expand check
40787 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
40788 this.queueExpand(node);
40789 }else if(pt != "append"){
40790 this.cancelExpand();
40793 // set the insert point style on the target node
40794 var returnCls = this.dropNotAllowed;
40795 if(this.isValidDropPoint(n, pt, dd, e, data)){
40800 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
40801 cls = "x-tree-drag-insert-above";
40802 }else if(pt == "below"){
40803 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
40804 cls = "x-tree-drag-insert-below";
40806 returnCls = "x-tree-drop-ok-append";
40807 cls = "x-tree-drag-append";
40809 if(this.lastInsertClass != cls){
40810 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
40811 this.lastInsertClass = cls;
40818 onNodeOut : function(n, dd, e, data){
40820 this.cancelExpand();
40821 this.removeDropIndicators(n);
40824 onNodeDrop : function(n, dd, e, data){
40825 var point = this.getDropPoint(e, n, dd);
40826 var targetNode = n.node;
40827 targetNode.ui.startDrop();
40828 if(!this.isValidDropPoint(n, point, dd, e, data)){
40829 targetNode.ui.endDrop();
40832 // first try to find the drop node
40833 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
40836 target: targetNode,
40841 dropNode: dropNode,
40844 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
40845 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
40846 targetNode.ui.endDrop();
40849 // allow target changing
40850 targetNode = dropEvent.target;
40851 if(point == "append" && !targetNode.isExpanded()){
40852 targetNode.expand(false, null, function(){
40853 this.completeDrop(dropEvent);
40854 }.createDelegate(this));
40856 this.completeDrop(dropEvent);
40861 completeDrop : function(de){
40862 var ns = de.dropNode, p = de.point, t = de.target;
40863 if(!(ns instanceof Array)){
40867 for(var i = 0, len = ns.length; i < len; i++){
40870 t.parentNode.insertBefore(n, t);
40871 }else if(p == "below"){
40872 t.parentNode.insertBefore(n, t.nextSibling);
40878 if(this.tree.hlDrop){
40882 this.tree.fireEvent("nodedrop", de);
40885 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
40886 if(this.tree.hlDrop){
40887 dropNode.ui.focus();
40888 dropNode.ui.highlight();
40890 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
40893 getTree : function(){
40897 removeDropIndicators : function(n){
40900 Roo.fly(el).removeClass([
40901 "x-tree-drag-insert-above",
40902 "x-tree-drag-insert-below",
40903 "x-tree-drag-append"]);
40904 this.lastInsertClass = "_noclass";
40908 beforeDragDrop : function(target, e, id){
40909 this.cancelExpand();
40913 afterRepair : function(data){
40914 if(data && Roo.enableFx){
40915 data.node.ui.highlight();
40925 * Ext JS Library 1.1.1
40926 * Copyright(c) 2006-2007, Ext JS, LLC.
40928 * Originally Released Under LGPL - original licence link has changed is not relivant.
40931 * <script type="text/javascript">
40935 if(Roo.dd.DragZone){
40936 Roo.tree.TreeDragZone = function(tree, config){
40937 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
40941 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
40942 ddGroup : "TreeDD",
40944 onBeforeDrag : function(data, e){
40946 return n && n.draggable && !n.disabled;
40950 onInitDrag : function(e){
40951 var data = this.dragData;
40952 this.tree.getSelectionModel().select(data.node);
40953 this.proxy.update("");
40954 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
40955 this.tree.fireEvent("startdrag", this.tree, data.node, e);
40958 getRepairXY : function(e, data){
40959 return data.node.ui.getDDRepairXY();
40962 onEndDrag : function(data, e){
40963 this.tree.fireEvent("enddrag", this.tree, data.node, e);
40968 onValidDrop : function(dd, e, id){
40969 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
40973 beforeInvalidDrop : function(e, id){
40974 // this scrolls the original position back into view
40975 var sm = this.tree.getSelectionModel();
40976 sm.clearSelections();
40977 sm.select(this.dragData.node);
40982 * Ext JS Library 1.1.1
40983 * Copyright(c) 2006-2007, Ext JS, LLC.
40985 * Originally Released Under LGPL - original licence link has changed is not relivant.
40988 * <script type="text/javascript">
40991 * @class Roo.tree.TreeEditor
40992 * @extends Roo.Editor
40993 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
40994 * as the editor field.
40996 * @param {Object} config (used to be the tree panel.)
40997 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
40999 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
41000 * @cfg {Roo.form.TextField|Object} field The field configuration
41004 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
41007 if (oldconfig) { // old style..
41008 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
41011 tree = config.tree;
41012 config.field = config.field || {};
41013 config.field.xtype = 'TextField';
41014 field = Roo.factory(config.field, Roo.form);
41016 config = config || {};
41021 * @event beforenodeedit
41022 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
41023 * false from the handler of this event.
41024 * @param {Editor} this
41025 * @param {Roo.tree.Node} node
41027 "beforenodeedit" : true
41031 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
41035 tree.on('beforeclick', this.beforeNodeClick, this);
41036 tree.getTreeEl().on('mousedown', this.hide, this);
41037 this.on('complete', this.updateNode, this);
41038 this.on('beforestartedit', this.fitToTree, this);
41039 this.on('startedit', this.bindScroll, this, {delay:10});
41040 this.on('specialkey', this.onSpecialKey, this);
41043 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
41045 * @cfg {String} alignment
41046 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
41052 * @cfg {Boolean} hideEl
41053 * True to hide the bound element while the editor is displayed (defaults to false)
41057 * @cfg {String} cls
41058 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
41060 cls: "x-small-editor x-tree-editor",
41062 * @cfg {Boolean} shim
41063 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
41069 * @cfg {Number} maxWidth
41070 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
41071 * the containing tree element's size, it will be automatically limited for you to the container width, taking
41072 * scroll and client offsets into account prior to each edit.
41079 fitToTree : function(ed, el){
41080 var td = this.tree.getTreeEl().dom, nd = el.dom;
41081 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
41082 td.scrollLeft = nd.offsetLeft;
41086 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
41087 this.setSize(w, '');
41089 return this.fireEvent('beforenodeedit', this, this.editNode);
41094 triggerEdit : function(node){
41095 this.completeEdit();
41096 this.editNode = node;
41097 this.startEdit(node.ui.textNode, node.text);
41101 bindScroll : function(){
41102 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
41106 beforeNodeClick : function(node, e){
41107 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
41108 this.lastClick = new Date();
41109 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
41111 this.triggerEdit(node);
41118 updateNode : function(ed, value){
41119 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
41120 this.editNode.setText(value);
41124 onHide : function(){
41125 Roo.tree.TreeEditor.superclass.onHide.call(this);
41127 this.editNode.ui.focus();
41132 onSpecialKey : function(field, e){
41133 var k = e.getKey();
41137 }else if(k == e.ENTER && !e.hasModifier()){
41139 this.completeEdit();
41142 });//<Script type="text/javascript">
41145 * Ext JS Library 1.1.1
41146 * Copyright(c) 2006-2007, Ext JS, LLC.
41148 * Originally Released Under LGPL - original licence link has changed is not relivant.
41151 * <script type="text/javascript">
41155 * Not documented??? - probably should be...
41158 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
41159 //focus: Roo.emptyFn, // prevent odd scrolling behavior
41161 renderElements : function(n, a, targetNode, bulkRender){
41162 //consel.log("renderElements?");
41163 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
41165 var t = n.getOwnerTree();
41166 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
41168 var cols = t.columns;
41169 var bw = t.borderWidth;
41171 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
41172 var cb = typeof a.checked == "boolean";
41173 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
41174 var colcls = 'x-t-' + tid + '-c0';
41176 '<li class="x-tree-node">',
41179 '<div class="x-tree-node-el ', a.cls,'">',
41181 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
41184 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
41185 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
41186 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
41187 (a.icon ? ' x-tree-node-inline-icon' : ''),
41188 (a.iconCls ? ' '+a.iconCls : ''),
41189 '" unselectable="on" />',
41190 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
41191 (a.checked ? 'checked="checked" />' : ' />')) : ''),
41193 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
41194 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
41195 '<span unselectable="on" qtip="' + tx + '">',
41199 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
41200 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
41202 for(var i = 1, len = cols.length; i < len; i++){
41204 colcls = 'x-t-' + tid + '-c' +i;
41205 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
41206 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
41207 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
41213 '<div class="x-clear"></div></div>',
41214 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
41217 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
41218 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
41219 n.nextSibling.ui.getEl(), buf.join(""));
41221 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
41223 var el = this.wrap.firstChild;
41225 this.elNode = el.firstChild;
41226 this.ranchor = el.childNodes[1];
41227 this.ctNode = this.wrap.childNodes[1];
41228 var cs = el.firstChild.childNodes;
41229 this.indentNode = cs[0];
41230 this.ecNode = cs[1];
41231 this.iconNode = cs[2];
41234 this.checkbox = cs[3];
41237 this.anchor = cs[index];
41239 this.textNode = cs[index].firstChild;
41241 //el.on("click", this.onClick, this);
41242 //el.on("dblclick", this.onDblClick, this);
41245 // console.log(this);
41247 initEvents : function(){
41248 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
41251 var a = this.ranchor;
41253 var el = Roo.get(a);
41255 if(Roo.isOpera){ // opera render bug ignores the CSS
41256 el.setStyle("text-decoration", "none");
41259 el.on("click", this.onClick, this);
41260 el.on("dblclick", this.onDblClick, this);
41261 el.on("contextmenu", this.onContextMenu, this);
41265 /*onSelectedChange : function(state){
41268 this.addClass("x-tree-selected");
41271 this.removeClass("x-tree-selected");
41274 addClass : function(cls){
41276 Roo.fly(this.elRow).addClass(cls);
41282 removeClass : function(cls){
41284 Roo.fly(this.elRow).removeClass(cls);
41290 });//<Script type="text/javascript">
41294 * Ext JS Library 1.1.1
41295 * Copyright(c) 2006-2007, Ext JS, LLC.
41297 * Originally Released Under LGPL - original licence link has changed is not relivant.
41300 * <script type="text/javascript">
41305 * @class Roo.tree.ColumnTree
41306 * @extends Roo.data.TreePanel
41307 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
41308 * @cfg {int} borderWidth compined right/left border allowance
41310 * @param {String/HTMLElement/Element} el The container element
41311 * @param {Object} config
41313 Roo.tree.ColumnTree = function(el, config)
41315 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
41319 * Fire this event on a container when it resizes
41320 * @param {int} w Width
41321 * @param {int} h Height
41325 this.on('resize', this.onResize, this);
41328 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
41332 borderWidth: Roo.isBorderBox ? 0 : 2,
41335 render : function(){
41336 // add the header.....
41338 Roo.tree.ColumnTree.superclass.render.apply(this);
41340 this.el.addClass('x-column-tree');
41342 this.headers = this.el.createChild(
41343 {cls:'x-tree-headers'},this.innerCt.dom);
41345 var cols = this.columns, c;
41346 var totalWidth = 0;
41348 var len = cols.length;
41349 for(var i = 0; i < len; i++){
41351 totalWidth += c.width;
41352 this.headEls.push(this.headers.createChild({
41353 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
41355 cls:'x-tree-hd-text',
41358 style:'width:'+(c.width-this.borderWidth)+'px;'
41361 this.headers.createChild({cls:'x-clear'});
41362 // prevent floats from wrapping when clipped
41363 this.headers.setWidth(totalWidth);
41364 //this.innerCt.setWidth(totalWidth);
41365 this.innerCt.setStyle({ overflow: 'auto' });
41366 this.onResize(this.width, this.height);
41370 onResize : function(w,h)
41375 this.innerCt.setWidth(this.width);
41376 this.innerCt.setHeight(this.height-20);
41379 var cols = this.columns, c;
41380 var totalWidth = 0;
41382 var len = cols.length;
41383 for(var i = 0; i < len; i++){
41385 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
41386 // it's the expander..
41387 expEl = this.headEls[i];
41390 totalWidth += c.width;
41394 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
41396 this.headers.setWidth(w-20);
41405 * Ext JS Library 1.1.1
41406 * Copyright(c) 2006-2007, Ext JS, LLC.
41408 * Originally Released Under LGPL - original licence link has changed is not relivant.
41411 * <script type="text/javascript">
41415 * @class Roo.menu.Menu
41416 * @extends Roo.util.Observable
41417 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
41418 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
41420 * Creates a new Menu
41421 * @param {Object} config Configuration options
41423 Roo.menu.Menu = function(config){
41424 Roo.apply(this, config);
41425 this.id = this.id || Roo.id();
41428 * @event beforeshow
41429 * Fires before this menu is displayed
41430 * @param {Roo.menu.Menu} this
41434 * @event beforehide
41435 * Fires before this menu is hidden
41436 * @param {Roo.menu.Menu} this
41441 * Fires after this menu is displayed
41442 * @param {Roo.menu.Menu} this
41447 * Fires after this menu is hidden
41448 * @param {Roo.menu.Menu} this
41453 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
41454 * @param {Roo.menu.Menu} this
41455 * @param {Roo.menu.Item} menuItem The menu item that was clicked
41456 * @param {Roo.EventObject} e
41461 * Fires when the mouse is hovering over this menu
41462 * @param {Roo.menu.Menu} this
41463 * @param {Roo.EventObject} e
41464 * @param {Roo.menu.Item} menuItem The menu item that was clicked
41469 * Fires when the mouse exits this menu
41470 * @param {Roo.menu.Menu} this
41471 * @param {Roo.EventObject} e
41472 * @param {Roo.menu.Item} menuItem The menu item that was clicked
41477 * Fires when a menu item contained in this menu is clicked
41478 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
41479 * @param {Roo.EventObject} e
41483 if (this.registerMenu) {
41484 Roo.menu.MenuMgr.register(this);
41487 var mis = this.items;
41488 this.items = new Roo.util.MixedCollection();
41490 this.add.apply(this, mis);
41494 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
41496 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
41500 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
41501 * for bottom-right shadow (defaults to "sides")
41505 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
41506 * this menu (defaults to "tl-tr?")
41508 subMenuAlign : "tl-tr?",
41510 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
41511 * relative to its element of origin (defaults to "tl-bl?")
41513 defaultAlign : "tl-bl?",
41515 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
41517 allowOtherMenus : false,
41519 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
41521 registerMenu : true,
41526 render : function(){
41530 var el = this.el = new Roo.Layer({
41532 shadow:this.shadow,
41534 parentEl: this.parentEl || document.body,
41538 this.keyNav = new Roo.menu.MenuNav(this);
41541 el.addClass("x-menu-plain");
41544 el.addClass(this.cls);
41546 // generic focus element
41547 this.focusEl = el.createChild({
41548 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
41550 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
41551 //disabling touch- as it's causing issues ..
41552 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
41553 ul.on('click' , this.onClick, this);
41556 ul.on("mouseover", this.onMouseOver, this);
41557 ul.on("mouseout", this.onMouseOut, this);
41558 this.items.each(function(item){
41563 var li = document.createElement("li");
41564 li.className = "x-menu-list-item";
41565 ul.dom.appendChild(li);
41566 item.render(li, this);
41573 autoWidth : function(){
41574 var el = this.el, ul = this.ul;
41578 var w = this.width;
41581 }else if(Roo.isIE){
41582 el.setWidth(this.minWidth);
41583 var t = el.dom.offsetWidth; // force recalc
41584 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
41589 delayAutoWidth : function(){
41592 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
41594 this.awTask.delay(20);
41599 findTargetItem : function(e){
41600 var t = e.getTarget(".x-menu-list-item", this.ul, true);
41601 if(t && t.menuItemId){
41602 return this.items.get(t.menuItemId);
41607 onClick : function(e){
41608 Roo.log("menu.onClick");
41609 var t = this.findTargetItem(e);
41614 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
41615 if(t == this.activeItem && t.shouldDeactivate(e)){
41616 this.activeItem.deactivate();
41617 delete this.activeItem;
41621 this.setActiveItem(t, true);
41629 this.fireEvent("click", this, t, e);
41633 setActiveItem : function(item, autoExpand){
41634 if(item != this.activeItem){
41635 if(this.activeItem){
41636 this.activeItem.deactivate();
41638 this.activeItem = item;
41639 item.activate(autoExpand);
41640 }else if(autoExpand){
41646 tryActivate : function(start, step){
41647 var items = this.items;
41648 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
41649 var item = items.get(i);
41650 if(!item.disabled && item.canActivate){
41651 this.setActiveItem(item, false);
41659 onMouseOver : function(e){
41661 if(t = this.findTargetItem(e)){
41662 if(t.canActivate && !t.disabled){
41663 this.setActiveItem(t, true);
41666 this.fireEvent("mouseover", this, e, t);
41670 onMouseOut : function(e){
41672 if(t = this.findTargetItem(e)){
41673 if(t == this.activeItem && t.shouldDeactivate(e)){
41674 this.activeItem.deactivate();
41675 delete this.activeItem;
41678 this.fireEvent("mouseout", this, e, t);
41682 * Read-only. Returns true if the menu is currently displayed, else false.
41685 isVisible : function(){
41686 return this.el && !this.hidden;
41690 * Displays this menu relative to another element
41691 * @param {String/HTMLElement/Roo.Element} element The element to align to
41692 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
41693 * the element (defaults to this.defaultAlign)
41694 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
41696 show : function(el, pos, parentMenu){
41697 this.parentMenu = parentMenu;
41701 this.fireEvent("beforeshow", this);
41702 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
41706 * Displays this menu at a specific xy position
41707 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
41708 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
41710 showAt : function(xy, parentMenu, /* private: */_e){
41711 this.parentMenu = parentMenu;
41716 this.fireEvent("beforeshow", this);
41717 xy = this.el.adjustForConstraints(xy);
41721 this.hidden = false;
41723 this.fireEvent("show", this);
41726 focus : function(){
41728 this.doFocus.defer(50, this);
41732 doFocus : function(){
41734 this.focusEl.focus();
41739 * Hides this menu and optionally all parent menus
41740 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
41742 hide : function(deep){
41743 if(this.el && this.isVisible()){
41744 this.fireEvent("beforehide", this);
41745 if(this.activeItem){
41746 this.activeItem.deactivate();
41747 this.activeItem = null;
41750 this.hidden = true;
41751 this.fireEvent("hide", this);
41753 if(deep === true && this.parentMenu){
41754 this.parentMenu.hide(true);
41759 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
41760 * Any of the following are valid:
41762 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
41763 * <li>An HTMLElement object which will be converted to a menu item</li>
41764 * <li>A menu item config object that will be created as a new menu item</li>
41765 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
41766 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
41771 var menu = new Roo.menu.Menu();
41773 // Create a menu item to add by reference
41774 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
41776 // Add a bunch of items at once using different methods.
41777 // Only the last item added will be returned.
41778 var item = menu.add(
41779 menuItem, // add existing item by ref
41780 'Dynamic Item', // new TextItem
41781 '-', // new separator
41782 { text: 'Config Item' } // new item by config
41785 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
41786 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
41789 var a = arguments, l = a.length, item;
41790 for(var i = 0; i < l; i++){
41792 if ((typeof(el) == "object") && el.xtype && el.xns) {
41793 el = Roo.factory(el, Roo.menu);
41796 if(el.render){ // some kind of Item
41797 item = this.addItem(el);
41798 }else if(typeof el == "string"){ // string
41799 if(el == "separator" || el == "-"){
41800 item = this.addSeparator();
41802 item = this.addText(el);
41804 }else if(el.tagName || el.el){ // element
41805 item = this.addElement(el);
41806 }else if(typeof el == "object"){ // must be menu item config?
41807 item = this.addMenuItem(el);
41814 * Returns this menu's underlying {@link Roo.Element} object
41815 * @return {Roo.Element} The element
41817 getEl : function(){
41825 * Adds a separator bar to the menu
41826 * @return {Roo.menu.Item} The menu item that was added
41828 addSeparator : function(){
41829 return this.addItem(new Roo.menu.Separator());
41833 * Adds an {@link Roo.Element} object to the menu
41834 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
41835 * @return {Roo.menu.Item} The menu item that was added
41837 addElement : function(el){
41838 return this.addItem(new Roo.menu.BaseItem(el));
41842 * Adds an existing object based on {@link Roo.menu.Item} to the menu
41843 * @param {Roo.menu.Item} item The menu item to add
41844 * @return {Roo.menu.Item} The menu item that was added
41846 addItem : function(item){
41847 this.items.add(item);
41849 var li = document.createElement("li");
41850 li.className = "x-menu-list-item";
41851 this.ul.dom.appendChild(li);
41852 item.render(li, this);
41853 this.delayAutoWidth();
41859 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
41860 * @param {Object} config A MenuItem config object
41861 * @return {Roo.menu.Item} The menu item that was added
41863 addMenuItem : function(config){
41864 if(!(config instanceof Roo.menu.Item)){
41865 if(typeof config.checked == "boolean"){ // must be check menu item config?
41866 config = new Roo.menu.CheckItem(config);
41868 config = new Roo.menu.Item(config);
41871 return this.addItem(config);
41875 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
41876 * @param {String} text The text to display in the menu item
41877 * @return {Roo.menu.Item} The menu item that was added
41879 addText : function(text){
41880 return this.addItem(new Roo.menu.TextItem({ text : text }));
41884 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
41885 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
41886 * @param {Roo.menu.Item} item The menu item to add
41887 * @return {Roo.menu.Item} The menu item that was added
41889 insert : function(index, item){
41890 this.items.insert(index, item);
41892 var li = document.createElement("li");
41893 li.className = "x-menu-list-item";
41894 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
41895 item.render(li, this);
41896 this.delayAutoWidth();
41902 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
41903 * @param {Roo.menu.Item} item The menu item to remove
41905 remove : function(item){
41906 this.items.removeKey(item.id);
41911 * Removes and destroys all items in the menu
41913 removeAll : function(){
41915 while(f = this.items.first()){
41921 // MenuNav is a private utility class used internally by the Menu
41922 Roo.menu.MenuNav = function(menu){
41923 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
41924 this.scope = this.menu = menu;
41927 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
41928 doRelay : function(e, h){
41929 var k = e.getKey();
41930 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
41931 this.menu.tryActivate(0, 1);
41934 return h.call(this.scope || this, e, this.menu);
41937 up : function(e, m){
41938 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
41939 m.tryActivate(m.items.length-1, -1);
41943 down : function(e, m){
41944 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
41945 m.tryActivate(0, 1);
41949 right : function(e, m){
41951 m.activeItem.expandMenu(true);
41955 left : function(e, m){
41957 if(m.parentMenu && m.parentMenu.activeItem){
41958 m.parentMenu.activeItem.activate();
41962 enter : function(e, m){
41964 e.stopPropagation();
41965 m.activeItem.onClick(e);
41966 m.fireEvent("click", this, m.activeItem);
41972 * Ext JS Library 1.1.1
41973 * Copyright(c) 2006-2007, Ext JS, LLC.
41975 * Originally Released Under LGPL - original licence link has changed is not relivant.
41978 * <script type="text/javascript">
41982 * @class Roo.menu.MenuMgr
41983 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
41986 Roo.menu.MenuMgr = function(){
41987 var menus, active, groups = {}, attached = false, lastShow = new Date();
41989 // private - called when first menu is created
41992 active = new Roo.util.MixedCollection();
41993 Roo.get(document).addKeyListener(27, function(){
41994 if(active.length > 0){
42001 function hideAll(){
42002 if(active && active.length > 0){
42003 var c = active.clone();
42004 c.each(function(m){
42011 function onHide(m){
42013 if(active.length < 1){
42014 Roo.get(document).un("mousedown", onMouseDown);
42020 function onShow(m){
42021 var last = active.last();
42022 lastShow = new Date();
42025 Roo.get(document).on("mousedown", onMouseDown);
42029 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
42030 m.parentMenu.activeChild = m;
42031 }else if(last && last.isVisible()){
42032 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
42037 function onBeforeHide(m){
42039 m.activeChild.hide();
42041 if(m.autoHideTimer){
42042 clearTimeout(m.autoHideTimer);
42043 delete m.autoHideTimer;
42048 function onBeforeShow(m){
42049 var pm = m.parentMenu;
42050 if(!pm && !m.allowOtherMenus){
42052 }else if(pm && pm.activeChild && active != m){
42053 pm.activeChild.hide();
42058 function onMouseDown(e){
42059 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
42065 function onBeforeCheck(mi, state){
42067 var g = groups[mi.group];
42068 for(var i = 0, l = g.length; i < l; i++){
42070 g[i].setChecked(false);
42079 * Hides all menus that are currently visible
42081 hideAll : function(){
42086 register : function(menu){
42090 menus[menu.id] = menu;
42091 menu.on("beforehide", onBeforeHide);
42092 menu.on("hide", onHide);
42093 menu.on("beforeshow", onBeforeShow);
42094 menu.on("show", onShow);
42095 var g = menu.group;
42096 if(g && menu.events["checkchange"]){
42100 groups[g].push(menu);
42101 menu.on("checkchange", onCheck);
42106 * Returns a {@link Roo.menu.Menu} object
42107 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
42108 * be used to generate and return a new Menu instance.
42110 get : function(menu){
42111 if(typeof menu == "string"){ // menu id
42112 return menus[menu];
42113 }else if(menu.events){ // menu instance
42115 }else if(typeof menu.length == 'number'){ // array of menu items?
42116 return new Roo.menu.Menu({items:menu});
42117 }else{ // otherwise, must be a config
42118 return new Roo.menu.Menu(menu);
42123 unregister : function(menu){
42124 delete menus[menu.id];
42125 menu.un("beforehide", onBeforeHide);
42126 menu.un("hide", onHide);
42127 menu.un("beforeshow", onBeforeShow);
42128 menu.un("show", onShow);
42129 var g = menu.group;
42130 if(g && menu.events["checkchange"]){
42131 groups[g].remove(menu);
42132 menu.un("checkchange", onCheck);
42137 registerCheckable : function(menuItem){
42138 var g = menuItem.group;
42143 groups[g].push(menuItem);
42144 menuItem.on("beforecheckchange", onBeforeCheck);
42149 unregisterCheckable : function(menuItem){
42150 var g = menuItem.group;
42152 groups[g].remove(menuItem);
42153 menuItem.un("beforecheckchange", onBeforeCheck);
42159 * Ext JS Library 1.1.1
42160 * Copyright(c) 2006-2007, Ext JS, LLC.
42162 * Originally Released Under LGPL - original licence link has changed is not relivant.
42165 * <script type="text/javascript">
42170 * @class Roo.menu.BaseItem
42171 * @extends Roo.Component
42172 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
42173 * management and base configuration options shared by all menu components.
42175 * Creates a new BaseItem
42176 * @param {Object} config Configuration options
42178 Roo.menu.BaseItem = function(config){
42179 Roo.menu.BaseItem.superclass.constructor.call(this, config);
42184 * Fires when this item is clicked
42185 * @param {Roo.menu.BaseItem} this
42186 * @param {Roo.EventObject} e
42191 * Fires when this item is activated
42192 * @param {Roo.menu.BaseItem} this
42196 * @event deactivate
42197 * Fires when this item is deactivated
42198 * @param {Roo.menu.BaseItem} this
42204 this.on("click", this.handler, this.scope, true);
42208 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
42210 * @cfg {Function} handler
42211 * A function that will handle the click event of this menu item (defaults to undefined)
42214 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
42216 canActivate : false,
42219 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
42224 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
42226 activeClass : "x-menu-item-active",
42228 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
42230 hideOnClick : true,
42232 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
42237 ctype: "Roo.menu.BaseItem",
42240 actionMode : "container",
42243 render : function(container, parentMenu){
42244 this.parentMenu = parentMenu;
42245 Roo.menu.BaseItem.superclass.render.call(this, container);
42246 this.container.menuItemId = this.id;
42250 onRender : function(container, position){
42251 this.el = Roo.get(this.el);
42252 container.dom.appendChild(this.el.dom);
42256 onClick : function(e){
42257 if(!this.disabled && this.fireEvent("click", this, e) !== false
42258 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
42259 this.handleClick(e);
42266 activate : function(){
42270 var li = this.container;
42271 li.addClass(this.activeClass);
42272 this.region = li.getRegion().adjust(2, 2, -2, -2);
42273 this.fireEvent("activate", this);
42278 deactivate : function(){
42279 this.container.removeClass(this.activeClass);
42280 this.fireEvent("deactivate", this);
42284 shouldDeactivate : function(e){
42285 return !this.region || !this.region.contains(e.getPoint());
42289 handleClick : function(e){
42290 if(this.hideOnClick){
42291 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
42296 expandMenu : function(autoActivate){
42301 hideMenu : function(){
42306 * Ext JS Library 1.1.1
42307 * Copyright(c) 2006-2007, Ext JS, LLC.
42309 * Originally Released Under LGPL - original licence link has changed is not relivant.
42312 * <script type="text/javascript">
42316 * @class Roo.menu.Adapter
42317 * @extends Roo.menu.BaseItem
42318 * 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.
42319 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
42321 * Creates a new Adapter
42322 * @param {Object} config Configuration options
42324 Roo.menu.Adapter = function(component, config){
42325 Roo.menu.Adapter.superclass.constructor.call(this, config);
42326 this.component = component;
42328 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
42330 canActivate : true,
42333 onRender : function(container, position){
42334 this.component.render(container);
42335 this.el = this.component.getEl();
42339 activate : function(){
42343 this.component.focus();
42344 this.fireEvent("activate", this);
42349 deactivate : function(){
42350 this.fireEvent("deactivate", this);
42354 disable : function(){
42355 this.component.disable();
42356 Roo.menu.Adapter.superclass.disable.call(this);
42360 enable : function(){
42361 this.component.enable();
42362 Roo.menu.Adapter.superclass.enable.call(this);
42366 * Ext JS Library 1.1.1
42367 * Copyright(c) 2006-2007, Ext JS, LLC.
42369 * Originally Released Under LGPL - original licence link has changed is not relivant.
42372 * <script type="text/javascript">
42376 * @class Roo.menu.TextItem
42377 * @extends Roo.menu.BaseItem
42378 * Adds a static text string to a menu, usually used as either a heading or group separator.
42379 * Note: old style constructor with text is still supported.
42382 * Creates a new TextItem
42383 * @param {Object} cfg Configuration
42385 Roo.menu.TextItem = function(cfg){
42386 if (typeof(cfg) == 'string') {
42389 Roo.apply(this,cfg);
42392 Roo.menu.TextItem.superclass.constructor.call(this);
42395 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
42397 * @cfg {Boolean} text Text to show on item.
42402 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
42404 hideOnClick : false,
42406 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
42408 itemCls : "x-menu-text",
42411 onRender : function(){
42412 var s = document.createElement("span");
42413 s.className = this.itemCls;
42414 s.innerHTML = this.text;
42416 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
42420 * Ext JS Library 1.1.1
42421 * Copyright(c) 2006-2007, Ext JS, LLC.
42423 * Originally Released Under LGPL - original licence link has changed is not relivant.
42426 * <script type="text/javascript">
42430 * @class Roo.menu.Separator
42431 * @extends Roo.menu.BaseItem
42432 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
42433 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
42435 * @param {Object} config Configuration options
42437 Roo.menu.Separator = function(config){
42438 Roo.menu.Separator.superclass.constructor.call(this, config);
42441 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
42443 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
42445 itemCls : "x-menu-sep",
42447 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
42449 hideOnClick : false,
42452 onRender : function(li){
42453 var s = document.createElement("span");
42454 s.className = this.itemCls;
42455 s.innerHTML = " ";
42457 li.addClass("x-menu-sep-li");
42458 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
42462 * Ext JS Library 1.1.1
42463 * Copyright(c) 2006-2007, Ext JS, LLC.
42465 * Originally Released Under LGPL - original licence link has changed is not relivant.
42468 * <script type="text/javascript">
42471 * @class Roo.menu.Item
42472 * @extends Roo.menu.BaseItem
42473 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
42474 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
42475 * activation and click handling.
42477 * Creates a new Item
42478 * @param {Object} config Configuration options
42480 Roo.menu.Item = function(config){
42481 Roo.menu.Item.superclass.constructor.call(this, config);
42483 this.menu = Roo.menu.MenuMgr.get(this.menu);
42486 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
42489 * @cfg {String} text
42490 * The text to show on the menu item.
42494 * @cfg {String} HTML to render in menu
42495 * The text to show on the menu item (HTML version).
42499 * @cfg {String} icon
42500 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
42504 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
42506 itemCls : "x-menu-item",
42508 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
42510 canActivate : true,
42512 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
42515 // doc'd in BaseItem
42519 ctype: "Roo.menu.Item",
42522 onRender : function(container, position){
42523 var el = document.createElement("a");
42524 el.hideFocus = true;
42525 el.unselectable = "on";
42526 el.href = this.href || "#";
42527 if(this.hrefTarget){
42528 el.target = this.hrefTarget;
42530 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
42532 var html = this.html.length ? this.html : String.format('{0}',this.text);
42534 el.innerHTML = String.format(
42535 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
42536 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
42538 Roo.menu.Item.superclass.onRender.call(this, container, position);
42542 * Sets the text to display in this menu item
42543 * @param {String} text The text to display
42544 * @param {Boolean} isHTML true to indicate text is pure html.
42546 setText : function(text, isHTML){
42554 var html = this.html.length ? this.html : String.format('{0}',this.text);
42556 this.el.update(String.format(
42557 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
42558 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
42559 this.parentMenu.autoWidth();
42564 handleClick : function(e){
42565 if(!this.href){ // if no link defined, stop the event automatically
42568 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
42572 activate : function(autoExpand){
42573 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
42583 shouldDeactivate : function(e){
42584 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
42585 if(this.menu && this.menu.isVisible()){
42586 return !this.menu.getEl().getRegion().contains(e.getPoint());
42594 deactivate : function(){
42595 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
42600 expandMenu : function(autoActivate){
42601 if(!this.disabled && this.menu){
42602 clearTimeout(this.hideTimer);
42603 delete this.hideTimer;
42604 if(!this.menu.isVisible() && !this.showTimer){
42605 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
42606 }else if (this.menu.isVisible() && autoActivate){
42607 this.menu.tryActivate(0, 1);
42613 deferExpand : function(autoActivate){
42614 delete this.showTimer;
42615 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
42617 this.menu.tryActivate(0, 1);
42622 hideMenu : function(){
42623 clearTimeout(this.showTimer);
42624 delete this.showTimer;
42625 if(!this.hideTimer && this.menu && this.menu.isVisible()){
42626 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
42631 deferHide : function(){
42632 delete this.hideTimer;
42637 * Ext JS Library 1.1.1
42638 * Copyright(c) 2006-2007, Ext JS, LLC.
42640 * Originally Released Under LGPL - original licence link has changed is not relivant.
42643 * <script type="text/javascript">
42647 * @class Roo.menu.CheckItem
42648 * @extends Roo.menu.Item
42649 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
42651 * Creates a new CheckItem
42652 * @param {Object} config Configuration options
42654 Roo.menu.CheckItem = function(config){
42655 Roo.menu.CheckItem.superclass.constructor.call(this, config);
42658 * @event beforecheckchange
42659 * Fires before the checked value is set, providing an opportunity to cancel if needed
42660 * @param {Roo.menu.CheckItem} this
42661 * @param {Boolean} checked The new checked value that will be set
42663 "beforecheckchange" : true,
42665 * @event checkchange
42666 * Fires after the checked value has been set
42667 * @param {Roo.menu.CheckItem} this
42668 * @param {Boolean} checked The checked value that was set
42670 "checkchange" : true
42672 if(this.checkHandler){
42673 this.on('checkchange', this.checkHandler, this.scope);
42676 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
42678 * @cfg {String} group
42679 * All check items with the same group name will automatically be grouped into a single-select
42680 * radio button group (defaults to '')
42683 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
42685 itemCls : "x-menu-item x-menu-check-item",
42687 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
42689 groupClass : "x-menu-group-item",
42692 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
42693 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
42694 * initialized with checked = true will be rendered as checked.
42699 ctype: "Roo.menu.CheckItem",
42702 onRender : function(c){
42703 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
42705 this.el.addClass(this.groupClass);
42707 Roo.menu.MenuMgr.registerCheckable(this);
42709 this.checked = false;
42710 this.setChecked(true, true);
42715 destroy : function(){
42717 Roo.menu.MenuMgr.unregisterCheckable(this);
42719 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
42723 * Set the checked state of this item
42724 * @param {Boolean} checked The new checked value
42725 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
42727 setChecked : function(state, suppressEvent){
42728 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
42729 if(this.container){
42730 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
42732 this.checked = state;
42733 if(suppressEvent !== true){
42734 this.fireEvent("checkchange", this, state);
42740 handleClick : function(e){
42741 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
42742 this.setChecked(!this.checked);
42744 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
42748 * Ext JS Library 1.1.1
42749 * Copyright(c) 2006-2007, Ext JS, LLC.
42751 * Originally Released Under LGPL - original licence link has changed is not relivant.
42754 * <script type="text/javascript">
42758 * @class Roo.menu.DateItem
42759 * @extends Roo.menu.Adapter
42760 * A menu item that wraps the {@link Roo.DatPicker} component.
42762 * Creates a new DateItem
42763 * @param {Object} config Configuration options
42765 Roo.menu.DateItem = function(config){
42766 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
42767 /** The Roo.DatePicker object @type Roo.DatePicker */
42768 this.picker = this.component;
42769 this.addEvents({select: true});
42771 this.picker.on("render", function(picker){
42772 picker.getEl().swallowEvent("click");
42773 picker.container.addClass("x-menu-date-item");
42776 this.picker.on("select", this.onSelect, this);
42779 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
42781 onSelect : function(picker, date){
42782 this.fireEvent("select", this, date, picker);
42783 Roo.menu.DateItem.superclass.handleClick.call(this);
42787 * Ext JS Library 1.1.1
42788 * Copyright(c) 2006-2007, Ext JS, LLC.
42790 * Originally Released Under LGPL - original licence link has changed is not relivant.
42793 * <script type="text/javascript">
42797 * @class Roo.menu.ColorItem
42798 * @extends Roo.menu.Adapter
42799 * A menu item that wraps the {@link Roo.ColorPalette} component.
42801 * Creates a new ColorItem
42802 * @param {Object} config Configuration options
42804 Roo.menu.ColorItem = function(config){
42805 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
42806 /** The Roo.ColorPalette object @type Roo.ColorPalette */
42807 this.palette = this.component;
42808 this.relayEvents(this.palette, ["select"]);
42809 if(this.selectHandler){
42810 this.on('select', this.selectHandler, this.scope);
42813 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
42815 * Ext JS Library 1.1.1
42816 * Copyright(c) 2006-2007, Ext JS, LLC.
42818 * Originally Released Under LGPL - original licence link has changed is not relivant.
42821 * <script type="text/javascript">
42826 * @class Roo.menu.DateMenu
42827 * @extends Roo.menu.Menu
42828 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
42830 * Creates a new DateMenu
42831 * @param {Object} config Configuration options
42833 Roo.menu.DateMenu = function(config){
42834 Roo.menu.DateMenu.superclass.constructor.call(this, config);
42836 var di = new Roo.menu.DateItem(config);
42839 * The {@link Roo.DatePicker} instance for this DateMenu
42842 this.picker = di.picker;
42845 * @param {DatePicker} picker
42846 * @param {Date} date
42848 this.relayEvents(di, ["select"]);
42849 this.on('beforeshow', function(){
42851 this.picker.hideMonthPicker(false);
42855 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
42859 * Ext JS Library 1.1.1
42860 * Copyright(c) 2006-2007, Ext JS, LLC.
42862 * Originally Released Under LGPL - original licence link has changed is not relivant.
42865 * <script type="text/javascript">
42870 * @class Roo.menu.ColorMenu
42871 * @extends Roo.menu.Menu
42872 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
42874 * Creates a new ColorMenu
42875 * @param {Object} config Configuration options
42877 Roo.menu.ColorMenu = function(config){
42878 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
42880 var ci = new Roo.menu.ColorItem(config);
42883 * The {@link Roo.ColorPalette} instance for this ColorMenu
42884 * @type ColorPalette
42886 this.palette = ci.palette;
42889 * @param {ColorPalette} palette
42890 * @param {String} color
42892 this.relayEvents(ci, ["select"]);
42894 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
42896 * Ext JS Library 1.1.1
42897 * Copyright(c) 2006-2007, Ext JS, LLC.
42899 * Originally Released Under LGPL - original licence link has changed is not relivant.
42902 * <script type="text/javascript">
42906 * @class Roo.form.Field
42907 * @extends Roo.BoxComponent
42908 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
42910 * Creates a new Field
42911 * @param {Object} config Configuration options
42913 Roo.form.Field = function(config){
42914 Roo.form.Field.superclass.constructor.call(this, config);
42917 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
42919 * @cfg {String} fieldLabel Label to use when rendering a form.
42922 * @cfg {String} qtip Mouse over tip
42926 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
42928 invalidClass : "x-form-invalid",
42930 * @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")
42932 invalidText : "The value in this field is invalid",
42934 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
42936 focusClass : "x-form-focus",
42938 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
42939 automatic validation (defaults to "keyup").
42941 validationEvent : "keyup",
42943 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
42945 validateOnBlur : true,
42947 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
42949 validationDelay : 250,
42951 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42952 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
42954 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
42956 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
42958 fieldClass : "x-form-field",
42960 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
42963 ----------- ----------------------------------------------------------------------
42964 qtip Display a quick tip when the user hovers over the field
42965 title Display a default browser title attribute popup
42966 under Add a block div beneath the field containing the error text
42967 side Add an error icon to the right of the field with a popup on hover
42968 [element id] Add the error text directly to the innerHTML of the specified element
42971 msgTarget : 'qtip',
42973 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
42978 * @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.
42983 * @cfg {Boolean} disabled True to disable the field (defaults to false).
42988 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
42990 inputType : undefined,
42993 * @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).
42995 tabIndex : undefined,
42998 isFormField : true,
43003 * @property {Roo.Element} fieldEl
43004 * Element Containing the rendered Field (with label etc.)
43007 * @cfg {Mixed} value A value to initialize this field with.
43012 * @cfg {String} name The field's HTML name attribute.
43015 * @cfg {String} cls A CSS class to apply to the field's underlying element.
43018 loadedValue : false,
43022 initComponent : function(){
43023 Roo.form.Field.superclass.initComponent.call(this);
43027 * Fires when this field receives input focus.
43028 * @param {Roo.form.Field} this
43033 * Fires when this field loses input focus.
43034 * @param {Roo.form.Field} this
43038 * @event specialkey
43039 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
43040 * {@link Roo.EventObject#getKey} to determine which key was pressed.
43041 * @param {Roo.form.Field} this
43042 * @param {Roo.EventObject} e The event object
43047 * Fires just before the field blurs if the field value has changed.
43048 * @param {Roo.form.Field} this
43049 * @param {Mixed} newValue The new value
43050 * @param {Mixed} oldValue The original value
43055 * Fires after the field has been marked as invalid.
43056 * @param {Roo.form.Field} this
43057 * @param {String} msg The validation message
43062 * Fires after the field has been validated with no errors.
43063 * @param {Roo.form.Field} this
43068 * Fires after the key up
43069 * @param {Roo.form.Field} this
43070 * @param {Roo.EventObject} e The event Object
43077 * Returns the name attribute of the field if available
43078 * @return {String} name The field name
43080 getName: function(){
43081 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
43085 onRender : function(ct, position){
43086 Roo.form.Field.superclass.onRender.call(this, ct, position);
43088 var cfg = this.getAutoCreate();
43090 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
43092 if (!cfg.name.length) {
43095 if(this.inputType){
43096 cfg.type = this.inputType;
43098 this.el = ct.createChild(cfg, position);
43100 var type = this.el.dom.type;
43102 if(type == 'password'){
43105 this.el.addClass('x-form-'+type);
43108 this.el.dom.readOnly = true;
43110 if(this.tabIndex !== undefined){
43111 this.el.dom.setAttribute('tabIndex', this.tabIndex);
43114 this.el.addClass([this.fieldClass, this.cls]);
43119 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
43120 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
43121 * @return {Roo.form.Field} this
43123 applyTo : function(target){
43124 this.allowDomMove = false;
43125 this.el = Roo.get(target);
43126 this.render(this.el.dom.parentNode);
43131 initValue : function(){
43132 if(this.value !== undefined){
43133 this.setValue(this.value);
43134 }else if(this.el.dom.value.length > 0){
43135 this.setValue(this.el.dom.value);
43140 * Returns true if this field has been changed since it was originally loaded and is not disabled.
43141 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
43143 isDirty : function() {
43144 if(this.disabled) {
43147 return String(this.getValue()) !== String(this.originalValue);
43151 * stores the current value in loadedValue
43153 resetHasChanged : function()
43155 this.loadedValue = String(this.getValue());
43158 * checks the current value against the 'loaded' value.
43159 * Note - will return false if 'resetHasChanged' has not been called first.
43161 hasChanged : function()
43163 if(this.disabled || this.readOnly) {
43166 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
43172 afterRender : function(){
43173 Roo.form.Field.superclass.afterRender.call(this);
43178 fireKey : function(e){
43179 //Roo.log('field ' + e.getKey());
43180 if(e.isNavKeyPress()){
43181 this.fireEvent("specialkey", this, e);
43186 * Resets the current field value to the originally loaded value and clears any validation messages
43188 reset : function(){
43189 this.setValue(this.resetValue);
43190 this.clearInvalid();
43194 initEvents : function(){
43195 // safari killled keypress - so keydown is now used..
43196 this.el.on("keydown" , this.fireKey, this);
43197 this.el.on("focus", this.onFocus, this);
43198 this.el.on("blur", this.onBlur, this);
43199 this.el.relayEvent('keyup', this);
43201 // reference to original value for reset
43202 this.originalValue = this.getValue();
43203 this.resetValue = this.getValue();
43207 onFocus : function(){
43208 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
43209 this.el.addClass(this.focusClass);
43211 if(!this.hasFocus){
43212 this.hasFocus = true;
43213 this.startValue = this.getValue();
43214 this.fireEvent("focus", this);
43218 beforeBlur : Roo.emptyFn,
43221 onBlur : function(){
43223 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
43224 this.el.removeClass(this.focusClass);
43226 this.hasFocus = false;
43227 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
43230 var v = this.getValue();
43231 if(String(v) !== String(this.startValue)){
43232 this.fireEvent('change', this, v, this.startValue);
43234 this.fireEvent("blur", this);
43238 * Returns whether or not the field value is currently valid
43239 * @param {Boolean} preventMark True to disable marking the field invalid
43240 * @return {Boolean} True if the value is valid, else false
43242 isValid : function(preventMark){
43246 var restore = this.preventMark;
43247 this.preventMark = preventMark === true;
43248 var v = this.validateValue(this.processValue(this.getRawValue()));
43249 this.preventMark = restore;
43254 * Validates the field value
43255 * @return {Boolean} True if the value is valid, else false
43257 validate : function(){
43258 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
43259 this.clearInvalid();
43265 processValue : function(value){
43270 // Subclasses should provide the validation implementation by overriding this
43271 validateValue : function(value){
43276 * Mark this field as invalid
43277 * @param {String} msg The validation message
43279 markInvalid : function(msg){
43280 if(!this.rendered || this.preventMark){ // not rendered
43284 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
43286 obj.el.addClass(this.invalidClass);
43287 msg = msg || this.invalidText;
43288 switch(this.msgTarget){
43290 obj.el.dom.qtip = msg;
43291 obj.el.dom.qclass = 'x-form-invalid-tip';
43292 if(Roo.QuickTips){ // fix for floating editors interacting with DND
43293 Roo.QuickTips.enable();
43297 this.el.dom.title = msg;
43301 var elp = this.el.findParent('.x-form-element', 5, true);
43302 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
43303 this.errorEl.setWidth(elp.getWidth(true)-20);
43305 this.errorEl.update(msg);
43306 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
43309 if(!this.errorIcon){
43310 var elp = this.el.findParent('.x-form-element', 5, true);
43311 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
43313 this.alignErrorIcon();
43314 this.errorIcon.dom.qtip = msg;
43315 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
43316 this.errorIcon.show();
43317 this.on('resize', this.alignErrorIcon, this);
43320 var t = Roo.getDom(this.msgTarget);
43322 t.style.display = this.msgDisplay;
43325 this.fireEvent('invalid', this, msg);
43329 alignErrorIcon : function(){
43330 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
43334 * Clear any invalid styles/messages for this field
43336 clearInvalid : function(){
43337 if(!this.rendered || this.preventMark){ // not rendered
43340 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
43342 obj.el.removeClass(this.invalidClass);
43343 switch(this.msgTarget){
43345 obj.el.dom.qtip = '';
43348 this.el.dom.title = '';
43352 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
43356 if(this.errorIcon){
43357 this.errorIcon.dom.qtip = '';
43358 this.errorIcon.hide();
43359 this.un('resize', this.alignErrorIcon, this);
43363 var t = Roo.getDom(this.msgTarget);
43365 t.style.display = 'none';
43368 this.fireEvent('valid', this);
43372 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
43373 * @return {Mixed} value The field value
43375 getRawValue : function(){
43376 var v = this.el.getValue();
43382 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
43383 * @return {Mixed} value The field value
43385 getValue : function(){
43386 var v = this.el.getValue();
43392 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
43393 * @param {Mixed} value The value to set
43395 setRawValue : function(v){
43396 return this.el.dom.value = (v === null || v === undefined ? '' : v);
43400 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
43401 * @param {Mixed} value The value to set
43403 setValue : function(v){
43406 this.el.dom.value = (v === null || v === undefined ? '' : v);
43411 adjustSize : function(w, h){
43412 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
43413 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
43417 adjustWidth : function(tag, w){
43418 tag = tag.toLowerCase();
43419 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
43420 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
43421 if(tag == 'input'){
43424 if(tag == 'textarea'){
43427 }else if(Roo.isOpera){
43428 if(tag == 'input'){
43431 if(tag == 'textarea'){
43441 // anything other than normal should be considered experimental
43442 Roo.form.Field.msgFx = {
43444 show: function(msgEl, f){
43445 msgEl.setDisplayed('block');
43448 hide : function(msgEl, f){
43449 msgEl.setDisplayed(false).update('');
43454 show: function(msgEl, f){
43455 msgEl.slideIn('t', {stopFx:true});
43458 hide : function(msgEl, f){
43459 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
43464 show: function(msgEl, f){
43465 msgEl.fixDisplay();
43466 msgEl.alignTo(f.el, 'tl-tr');
43467 msgEl.slideIn('l', {stopFx:true});
43470 hide : function(msgEl, f){
43471 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
43476 * Ext JS Library 1.1.1
43477 * Copyright(c) 2006-2007, Ext JS, LLC.
43479 * Originally Released Under LGPL - original licence link has changed is not relivant.
43482 * <script type="text/javascript">
43487 * @class Roo.form.TextField
43488 * @extends Roo.form.Field
43489 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
43490 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
43492 * Creates a new TextField
43493 * @param {Object} config Configuration options
43495 Roo.form.TextField = function(config){
43496 Roo.form.TextField.superclass.constructor.call(this, config);
43500 * Fires when the autosize function is triggered. The field may or may not have actually changed size
43501 * according to the default logic, but this event provides a hook for the developer to apply additional
43502 * logic at runtime to resize the field if needed.
43503 * @param {Roo.form.Field} this This text field
43504 * @param {Number} width The new field width
43510 Roo.extend(Roo.form.TextField, Roo.form.Field, {
43512 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
43516 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
43520 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
43524 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
43528 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
43532 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
43534 disableKeyFilter : false,
43536 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
43540 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
43544 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
43546 maxLength : Number.MAX_VALUE,
43548 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
43550 minLengthText : "The minimum length for this field is {0}",
43552 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
43554 maxLengthText : "The maximum length for this field is {0}",
43556 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
43558 selectOnFocus : false,
43560 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
43562 blankText : "This field is required",
43564 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
43565 * If available, this function will be called only after the basic validators all return true, and will be passed the
43566 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
43570 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
43571 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
43572 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
43576 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
43580 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
43586 initEvents : function()
43588 if (this.emptyText) {
43589 this.el.attr('placeholder', this.emptyText);
43592 Roo.form.TextField.superclass.initEvents.call(this);
43593 if(this.validationEvent == 'keyup'){
43594 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
43595 this.el.on('keyup', this.filterValidation, this);
43597 else if(this.validationEvent !== false){
43598 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
43601 if(this.selectOnFocus){
43602 this.on("focus", this.preFocus, this);
43605 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
43606 this.el.on("keypress", this.filterKeys, this);
43609 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
43610 this.el.on("click", this.autoSize, this);
43612 if(this.el.is('input[type=password]') && Roo.isSafari){
43613 this.el.on('keydown', this.SafariOnKeyDown, this);
43617 processValue : function(value){
43618 if(this.stripCharsRe){
43619 var newValue = value.replace(this.stripCharsRe, '');
43620 if(newValue !== value){
43621 this.setRawValue(newValue);
43628 filterValidation : function(e){
43629 if(!e.isNavKeyPress()){
43630 this.validationTask.delay(this.validationDelay);
43635 onKeyUp : function(e){
43636 if(!e.isNavKeyPress()){
43642 * Resets the current field value to the originally-loaded value and clears any validation messages.
43645 reset : function(){
43646 Roo.form.TextField.superclass.reset.call(this);
43652 preFocus : function(){
43654 if(this.selectOnFocus){
43655 this.el.dom.select();
43661 filterKeys : function(e){
43662 var k = e.getKey();
43663 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
43666 var c = e.getCharCode(), cc = String.fromCharCode(c);
43667 if(Roo.isIE && (e.isSpecialKey() || !cc)){
43670 if(!this.maskRe.test(cc)){
43675 setValue : function(v){
43677 Roo.form.TextField.superclass.setValue.apply(this, arguments);
43683 * Validates a value according to the field's validation rules and marks the field as invalid
43684 * if the validation fails
43685 * @param {Mixed} value The value to validate
43686 * @return {Boolean} True if the value is valid, else false
43688 validateValue : function(value){
43689 if(value.length < 1) { // if it's blank
43690 if(this.allowBlank){
43691 this.clearInvalid();
43694 this.markInvalid(this.blankText);
43698 if(value.length < this.minLength){
43699 this.markInvalid(String.format(this.minLengthText, this.minLength));
43702 if(value.length > this.maxLength){
43703 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
43707 var vt = Roo.form.VTypes;
43708 if(!vt[this.vtype](value, this)){
43709 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
43713 if(typeof this.validator == "function"){
43714 var msg = this.validator(value);
43716 this.markInvalid(msg);
43720 if(this.regex && !this.regex.test(value)){
43721 this.markInvalid(this.regexText);
43728 * Selects text in this field
43729 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
43730 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
43732 selectText : function(start, end){
43733 var v = this.getRawValue();
43735 start = start === undefined ? 0 : start;
43736 end = end === undefined ? v.length : end;
43737 var d = this.el.dom;
43738 if(d.setSelectionRange){
43739 d.setSelectionRange(start, end);
43740 }else if(d.createTextRange){
43741 var range = d.createTextRange();
43742 range.moveStart("character", start);
43743 range.moveEnd("character", v.length-end);
43750 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
43751 * This only takes effect if grow = true, and fires the autosize event.
43753 autoSize : function(){
43754 if(!this.grow || !this.rendered){
43758 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
43761 var v = el.dom.value;
43762 var d = document.createElement('div');
43763 d.appendChild(document.createTextNode(v));
43767 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
43768 this.el.setWidth(w);
43769 this.fireEvent("autosize", this, w);
43773 SafariOnKeyDown : function(event)
43775 // this is a workaround for a password hang bug on chrome/ webkit.
43777 var isSelectAll = false;
43779 if(this.el.dom.selectionEnd > 0){
43780 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
43782 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
43783 event.preventDefault();
43788 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
43790 event.preventDefault();
43791 // this is very hacky as keydown always get's upper case.
43793 var cc = String.fromCharCode(event.getCharCode());
43796 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
43804 * Ext JS Library 1.1.1
43805 * Copyright(c) 2006-2007, Ext JS, LLC.
43807 * Originally Released Under LGPL - original licence link has changed is not relivant.
43810 * <script type="text/javascript">
43814 * @class Roo.form.Hidden
43815 * @extends Roo.form.TextField
43816 * Simple Hidden element used on forms
43818 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
43821 * Creates a new Hidden form element.
43822 * @param {Object} config Configuration options
43827 // easy hidden field...
43828 Roo.form.Hidden = function(config){
43829 Roo.form.Hidden.superclass.constructor.call(this, config);
43832 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
43834 inputType: 'hidden',
43837 labelSeparator: '',
43839 itemCls : 'x-form-item-display-none'
43847 * Ext JS Library 1.1.1
43848 * Copyright(c) 2006-2007, Ext JS, LLC.
43850 * Originally Released Under LGPL - original licence link has changed is not relivant.
43853 * <script type="text/javascript">
43857 * @class Roo.form.TriggerField
43858 * @extends Roo.form.TextField
43859 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
43860 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
43861 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
43862 * for which you can provide a custom implementation. For example:
43864 var trigger = new Roo.form.TriggerField();
43865 trigger.onTriggerClick = myTriggerFn;
43866 trigger.applyTo('my-field');
43869 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
43870 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
43871 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
43872 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
43874 * Create a new TriggerField.
43875 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
43876 * to the base TextField)
43878 Roo.form.TriggerField = function(config){
43879 this.mimicing = false;
43880 Roo.form.TriggerField.superclass.constructor.call(this, config);
43883 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
43885 * @cfg {String} triggerClass A CSS class to apply to the trigger
43888 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43889 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
43891 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
43893 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
43897 /** @cfg {Boolean} grow @hide */
43898 /** @cfg {Number} growMin @hide */
43899 /** @cfg {Number} growMax @hide */
43905 autoSize: Roo.emptyFn,
43909 deferHeight : true,
43912 actionMode : 'wrap',
43914 onResize : function(w, h){
43915 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
43916 if(typeof w == 'number'){
43917 var x = w - this.trigger.getWidth();
43918 this.el.setWidth(this.adjustWidth('input', x));
43919 this.trigger.setStyle('left', x+'px');
43924 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43927 getResizeEl : function(){
43932 getPositionEl : function(){
43937 alignErrorIcon : function(){
43938 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
43942 onRender : function(ct, position){
43943 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
43944 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
43945 this.trigger = this.wrap.createChild(this.triggerConfig ||
43946 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
43947 if(this.hideTrigger){
43948 this.trigger.setDisplayed(false);
43950 this.initTrigger();
43952 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
43957 initTrigger : function(){
43958 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
43959 this.trigger.addClassOnOver('x-form-trigger-over');
43960 this.trigger.addClassOnClick('x-form-trigger-click');
43964 onDestroy : function(){
43966 this.trigger.removeAllListeners();
43967 this.trigger.remove();
43970 this.wrap.remove();
43972 Roo.form.TriggerField.superclass.onDestroy.call(this);
43976 onFocus : function(){
43977 Roo.form.TriggerField.superclass.onFocus.call(this);
43978 if(!this.mimicing){
43979 this.wrap.addClass('x-trigger-wrap-focus');
43980 this.mimicing = true;
43981 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
43982 if(this.monitorTab){
43983 this.el.on("keydown", this.checkTab, this);
43989 checkTab : function(e){
43990 if(e.getKey() == e.TAB){
43991 this.triggerBlur();
43996 onBlur : function(){
44001 mimicBlur : function(e, t){
44002 if(!this.wrap.contains(t) && this.validateBlur()){
44003 this.triggerBlur();
44008 triggerBlur : function(){
44009 this.mimicing = false;
44010 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
44011 if(this.monitorTab){
44012 this.el.un("keydown", this.checkTab, this);
44014 this.wrap.removeClass('x-trigger-wrap-focus');
44015 Roo.form.TriggerField.superclass.onBlur.call(this);
44019 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
44020 validateBlur : function(e, t){
44025 onDisable : function(){
44026 Roo.form.TriggerField.superclass.onDisable.call(this);
44028 this.wrap.addClass('x-item-disabled');
44033 onEnable : function(){
44034 Roo.form.TriggerField.superclass.onEnable.call(this);
44036 this.wrap.removeClass('x-item-disabled');
44041 onShow : function(){
44042 var ae = this.getActionEl();
44045 ae.dom.style.display = '';
44046 ae.dom.style.visibility = 'visible';
44052 onHide : function(){
44053 var ae = this.getActionEl();
44054 ae.dom.style.display = 'none';
44058 * The function that should handle the trigger's click event. This method does nothing by default until overridden
44059 * by an implementing function.
44061 * @param {EventObject} e
44063 onTriggerClick : Roo.emptyFn
44066 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
44067 // to be extended by an implementing class. For an example of implementing this class, see the custom
44068 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
44069 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
44070 initComponent : function(){
44071 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
44073 this.triggerConfig = {
44074 tag:'span', cls:'x-form-twin-triggers', cn:[
44075 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
44076 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
44080 getTrigger : function(index){
44081 return this.triggers[index];
44084 initTrigger : function(){
44085 var ts = this.trigger.select('.x-form-trigger', true);
44086 this.wrap.setStyle('overflow', 'hidden');
44087 var triggerField = this;
44088 ts.each(function(t, all, index){
44089 t.hide = function(){
44090 var w = triggerField.wrap.getWidth();
44091 this.dom.style.display = 'none';
44092 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
44094 t.show = function(){
44095 var w = triggerField.wrap.getWidth();
44096 this.dom.style.display = '';
44097 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
44099 var triggerIndex = 'Trigger'+(index+1);
44101 if(this['hide'+triggerIndex]){
44102 t.dom.style.display = 'none';
44104 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
44105 t.addClassOnOver('x-form-trigger-over');
44106 t.addClassOnClick('x-form-trigger-click');
44108 this.triggers = ts.elements;
44111 onTrigger1Click : Roo.emptyFn,
44112 onTrigger2Click : Roo.emptyFn
44115 * Ext JS Library 1.1.1
44116 * Copyright(c) 2006-2007, Ext JS, LLC.
44118 * Originally Released Under LGPL - original licence link has changed is not relivant.
44121 * <script type="text/javascript">
44125 * @class Roo.form.TextArea
44126 * @extends Roo.form.TextField
44127 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
44128 * support for auto-sizing.
44130 * Creates a new TextArea
44131 * @param {Object} config Configuration options
44133 Roo.form.TextArea = function(config){
44134 Roo.form.TextArea.superclass.constructor.call(this, config);
44135 // these are provided exchanges for backwards compat
44136 // minHeight/maxHeight were replaced by growMin/growMax to be
44137 // compatible with TextField growing config values
44138 if(this.minHeight !== undefined){
44139 this.growMin = this.minHeight;
44141 if(this.maxHeight !== undefined){
44142 this.growMax = this.maxHeight;
44146 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
44148 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
44152 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
44156 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
44157 * in the field (equivalent to setting overflow: hidden, defaults to false)
44159 preventScrollbars: false,
44161 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44162 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
44166 onRender : function(ct, position){
44168 this.defaultAutoCreate = {
44170 style:"width:300px;height:60px;",
44171 autocomplete: "new-password"
44174 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
44176 this.textSizeEl = Roo.DomHelper.append(document.body, {
44177 tag: "pre", cls: "x-form-grow-sizer"
44179 if(this.preventScrollbars){
44180 this.el.setStyle("overflow", "hidden");
44182 this.el.setHeight(this.growMin);
44186 onDestroy : function(){
44187 if(this.textSizeEl){
44188 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
44190 Roo.form.TextArea.superclass.onDestroy.call(this);
44194 onKeyUp : function(e){
44195 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
44201 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
44202 * This only takes effect if grow = true, and fires the autosize event if the height changes.
44204 autoSize : function(){
44205 if(!this.grow || !this.textSizeEl){
44209 var v = el.dom.value;
44210 var ts = this.textSizeEl;
44213 ts.appendChild(document.createTextNode(v));
44216 Roo.fly(ts).setWidth(this.el.getWidth());
44218 v = "  ";
44221 v = v.replace(/\n/g, '<p> </p>');
44223 v += " \n ";
44226 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
44227 if(h != this.lastHeight){
44228 this.lastHeight = h;
44229 this.el.setHeight(h);
44230 this.fireEvent("autosize", this, h);
44235 * Ext JS Library 1.1.1
44236 * Copyright(c) 2006-2007, Ext JS, LLC.
44238 * Originally Released Under LGPL - original licence link has changed is not relivant.
44241 * <script type="text/javascript">
44246 * @class Roo.form.NumberField
44247 * @extends Roo.form.TextField
44248 * Numeric text field that provides automatic keystroke filtering and numeric validation.
44250 * Creates a new NumberField
44251 * @param {Object} config Configuration options
44253 Roo.form.NumberField = function(config){
44254 Roo.form.NumberField.superclass.constructor.call(this, config);
44257 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
44259 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
44261 fieldClass: "x-form-field x-form-num-field",
44263 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
44265 allowDecimals : true,
44267 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
44269 decimalSeparator : ".",
44271 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
44273 decimalPrecision : 2,
44275 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
44277 allowNegative : true,
44279 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
44281 minValue : Number.NEGATIVE_INFINITY,
44283 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
44285 maxValue : Number.MAX_VALUE,
44287 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
44289 minText : "The minimum value for this field is {0}",
44291 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
44293 maxText : "The maximum value for this field is {0}",
44295 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
44296 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
44298 nanText : "{0} is not a valid number",
44301 initEvents : function(){
44302 Roo.form.NumberField.superclass.initEvents.call(this);
44303 var allowed = "0123456789";
44304 if(this.allowDecimals){
44305 allowed += this.decimalSeparator;
44307 if(this.allowNegative){
44310 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
44311 var keyPress = function(e){
44312 var k = e.getKey();
44313 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
44316 var c = e.getCharCode();
44317 if(allowed.indexOf(String.fromCharCode(c)) === -1){
44321 this.el.on("keypress", keyPress, this);
44325 validateValue : function(value){
44326 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
44329 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
44332 var num = this.parseValue(value);
44334 this.markInvalid(String.format(this.nanText, value));
44337 if(num < this.minValue){
44338 this.markInvalid(String.format(this.minText, this.minValue));
44341 if(num > this.maxValue){
44342 this.markInvalid(String.format(this.maxText, this.maxValue));
44348 getValue : function(){
44349 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
44353 parseValue : function(value){
44354 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
44355 return isNaN(value) ? '' : value;
44359 fixPrecision : function(value){
44360 var nan = isNaN(value);
44361 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
44362 return nan ? '' : value;
44364 return parseFloat(value).toFixed(this.decimalPrecision);
44367 setValue : function(v){
44368 v = this.fixPrecision(v);
44369 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
44373 decimalPrecisionFcn : function(v){
44374 return Math.floor(v);
44377 beforeBlur : function(){
44378 var v = this.parseValue(this.getRawValue());
44385 * Ext JS Library 1.1.1
44386 * Copyright(c) 2006-2007, Ext JS, LLC.
44388 * Originally Released Under LGPL - original licence link has changed is not relivant.
44391 * <script type="text/javascript">
44395 * @class Roo.form.DateField
44396 * @extends Roo.form.TriggerField
44397 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
44399 * Create a new DateField
44400 * @param {Object} config
44402 Roo.form.DateField = function(config){
44403 Roo.form.DateField.superclass.constructor.call(this, config);
44409 * Fires when a date is selected
44410 * @param {Roo.form.DateField} combo This combo box
44411 * @param {Date} date The date selected
44418 if(typeof this.minValue == "string") {
44419 this.minValue = this.parseDate(this.minValue);
44421 if(typeof this.maxValue == "string") {
44422 this.maxValue = this.parseDate(this.maxValue);
44424 this.ddMatch = null;
44425 if(this.disabledDates){
44426 var dd = this.disabledDates;
44428 for(var i = 0; i < dd.length; i++){
44430 if(i != dd.length-1) {
44434 this.ddMatch = new RegExp(re + ")");
44438 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
44440 * @cfg {String} format
44441 * The default date format string which can be overriden for localization support. The format must be
44442 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
44446 * @cfg {String} altFormats
44447 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
44448 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
44450 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
44452 * @cfg {Array} disabledDays
44453 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
44455 disabledDays : null,
44457 * @cfg {String} disabledDaysText
44458 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
44460 disabledDaysText : "Disabled",
44462 * @cfg {Array} disabledDates
44463 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
44464 * expression so they are very powerful. Some examples:
44466 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
44467 * <li>["03/08", "09/16"] would disable those days for every year</li>
44468 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
44469 * <li>["03/../2006"] would disable every day in March 2006</li>
44470 * <li>["^03"] would disable every day in every March</li>
44472 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
44473 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
44475 disabledDates : null,
44477 * @cfg {String} disabledDatesText
44478 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
44480 disabledDatesText : "Disabled",
44482 * @cfg {Date/String} minValue
44483 * The minimum allowed date. Can be either a Javascript date object or a string date in a
44484 * valid format (defaults to null).
44488 * @cfg {Date/String} maxValue
44489 * The maximum allowed date. Can be either a Javascript date object or a string date in a
44490 * valid format (defaults to null).
44494 * @cfg {String} minText
44495 * The error text to display when the date in the cell is before minValue (defaults to
44496 * 'The date in this field must be after {minValue}').
44498 minText : "The date in this field must be equal to or after {0}",
44500 * @cfg {String} maxText
44501 * The error text to display when the date in the cell is after maxValue (defaults to
44502 * 'The date in this field must be before {maxValue}').
44504 maxText : "The date in this field must be equal to or before {0}",
44506 * @cfg {String} invalidText
44507 * The error text to display when the date in the field is invalid (defaults to
44508 * '{value} is not a valid date - it must be in the format {format}').
44510 invalidText : "{0} is not a valid date - it must be in the format {1}",
44512 * @cfg {String} triggerClass
44513 * An additional CSS class used to style the trigger button. The trigger will always get the
44514 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
44515 * which displays a calendar icon).
44517 triggerClass : 'x-form-date-trigger',
44521 * @cfg {Boolean} useIso
44522 * if enabled, then the date field will use a hidden field to store the
44523 * real value as iso formated date. default (false)
44527 * @cfg {String/Object} autoCreate
44528 * A DomHelper element spec, or true for a default element spec (defaults to
44529 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
44532 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
44535 hiddenField: false,
44537 onRender : function(ct, position)
44539 Roo.form.DateField.superclass.onRender.call(this, ct, position);
44541 //this.el.dom.removeAttribute('name');
44542 Roo.log("Changing name?");
44543 this.el.dom.setAttribute('name', this.name + '____hidden___' );
44544 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
44546 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
44547 // prevent input submission
44548 this.hiddenName = this.name;
44555 validateValue : function(value)
44557 value = this.formatDate(value);
44558 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
44559 Roo.log('super failed');
44562 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
44565 var svalue = value;
44566 value = this.parseDate(value);
44568 Roo.log('parse date failed' + svalue);
44569 this.markInvalid(String.format(this.invalidText, svalue, this.format));
44572 var time = value.getTime();
44573 if(this.minValue && time < this.minValue.getTime()){
44574 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
44577 if(this.maxValue && time > this.maxValue.getTime()){
44578 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
44581 if(this.disabledDays){
44582 var day = value.getDay();
44583 for(var i = 0; i < this.disabledDays.length; i++) {
44584 if(day === this.disabledDays[i]){
44585 this.markInvalid(this.disabledDaysText);
44590 var fvalue = this.formatDate(value);
44591 if(this.ddMatch && this.ddMatch.test(fvalue)){
44592 this.markInvalid(String.format(this.disabledDatesText, fvalue));
44599 // Provides logic to override the default TriggerField.validateBlur which just returns true
44600 validateBlur : function(){
44601 return !this.menu || !this.menu.isVisible();
44604 getName: function()
44606 // returns hidden if it's set..
44607 if (!this.rendered) {return ''};
44608 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
44613 * Returns the current date value of the date field.
44614 * @return {Date} The date value
44616 getValue : function(){
44618 return this.hiddenField ?
44619 this.hiddenField.value :
44620 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
44624 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
44625 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
44626 * (the default format used is "m/d/y").
44629 //All of these calls set the same date value (May 4, 2006)
44631 //Pass a date object:
44632 var dt = new Date('5/4/06');
44633 dateField.setValue(dt);
44635 //Pass a date string (default format):
44636 dateField.setValue('5/4/06');
44638 //Pass a date string (custom format):
44639 dateField.format = 'Y-m-d';
44640 dateField.setValue('2006-5-4');
44642 * @param {String/Date} date The date or valid date string
44644 setValue : function(date){
44645 if (this.hiddenField) {
44646 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
44648 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
44649 // make sure the value field is always stored as a date..
44650 this.value = this.parseDate(date);
44656 parseDate : function(value){
44657 if(!value || value instanceof Date){
44660 var v = Date.parseDate(value, this.format);
44661 if (!v && this.useIso) {
44662 v = Date.parseDate(value, 'Y-m-d');
44664 if(!v && this.altFormats){
44665 if(!this.altFormatsArray){
44666 this.altFormatsArray = this.altFormats.split("|");
44668 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
44669 v = Date.parseDate(value, this.altFormatsArray[i]);
44676 formatDate : function(date, fmt){
44677 return (!date || !(date instanceof Date)) ?
44678 date : date.dateFormat(fmt || this.format);
44683 select: function(m, d){
44686 this.fireEvent('select', this, d);
44688 show : function(){ // retain focus styling
44692 this.focus.defer(10, this);
44693 var ml = this.menuListeners;
44694 this.menu.un("select", ml.select, this);
44695 this.menu.un("show", ml.show, this);
44696 this.menu.un("hide", ml.hide, this);
44701 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
44702 onTriggerClick : function(){
44706 if(this.menu == null){
44707 this.menu = new Roo.menu.DateMenu();
44709 Roo.apply(this.menu.picker, {
44710 showClear: this.allowBlank,
44711 minDate : this.minValue,
44712 maxDate : this.maxValue,
44713 disabledDatesRE : this.ddMatch,
44714 disabledDatesText : this.disabledDatesText,
44715 disabledDays : this.disabledDays,
44716 disabledDaysText : this.disabledDaysText,
44717 format : this.useIso ? 'Y-m-d' : this.format,
44718 minText : String.format(this.minText, this.formatDate(this.minValue)),
44719 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
44721 this.menu.on(Roo.apply({}, this.menuListeners, {
44724 this.menu.picker.setValue(this.getValue() || new Date());
44725 this.menu.show(this.el, "tl-bl?");
44728 beforeBlur : function(){
44729 var v = this.parseDate(this.getRawValue());
44739 isDirty : function() {
44740 if(this.disabled) {
44744 if(typeof(this.startValue) === 'undefined'){
44748 return String(this.getValue()) !== String(this.startValue);
44753 * Ext JS Library 1.1.1
44754 * Copyright(c) 2006-2007, Ext JS, LLC.
44756 * Originally Released Under LGPL - original licence link has changed is not relivant.
44759 * <script type="text/javascript">
44763 * @class Roo.form.MonthField
44764 * @extends Roo.form.TriggerField
44765 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
44767 * Create a new MonthField
44768 * @param {Object} config
44770 Roo.form.MonthField = function(config){
44772 Roo.form.MonthField.superclass.constructor.call(this, config);
44778 * Fires when a date is selected
44779 * @param {Roo.form.MonthFieeld} combo This combo box
44780 * @param {Date} date The date selected
44787 if(typeof this.minValue == "string") {
44788 this.minValue = this.parseDate(this.minValue);
44790 if(typeof this.maxValue == "string") {
44791 this.maxValue = this.parseDate(this.maxValue);
44793 this.ddMatch = null;
44794 if(this.disabledDates){
44795 var dd = this.disabledDates;
44797 for(var i = 0; i < dd.length; i++){
44799 if(i != dd.length-1) {
44803 this.ddMatch = new RegExp(re + ")");
44807 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
44809 * @cfg {String} format
44810 * The default date format string which can be overriden for localization support. The format must be
44811 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
44815 * @cfg {String} altFormats
44816 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
44817 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
44819 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
44821 * @cfg {Array} disabledDays
44822 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
44824 disabledDays : [0,1,2,3,4,5,6],
44826 * @cfg {String} disabledDaysText
44827 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
44829 disabledDaysText : "Disabled",
44831 * @cfg {Array} disabledDates
44832 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
44833 * expression so they are very powerful. Some examples:
44835 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
44836 * <li>["03/08", "09/16"] would disable those days for every year</li>
44837 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
44838 * <li>["03/../2006"] would disable every day in March 2006</li>
44839 * <li>["^03"] would disable every day in every March</li>
44841 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
44842 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
44844 disabledDates : null,
44846 * @cfg {String} disabledDatesText
44847 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
44849 disabledDatesText : "Disabled",
44851 * @cfg {Date/String} minValue
44852 * The minimum allowed date. Can be either a Javascript date object or a string date in a
44853 * valid format (defaults to null).
44857 * @cfg {Date/String} maxValue
44858 * The maximum allowed date. Can be either a Javascript date object or a string date in a
44859 * valid format (defaults to null).
44863 * @cfg {String} minText
44864 * The error text to display when the date in the cell is before minValue (defaults to
44865 * 'The date in this field must be after {minValue}').
44867 minText : "The date in this field must be equal to or after {0}",
44869 * @cfg {String} maxTextf
44870 * The error text to display when the date in the cell is after maxValue (defaults to
44871 * 'The date in this field must be before {maxValue}').
44873 maxText : "The date in this field must be equal to or before {0}",
44875 * @cfg {String} invalidText
44876 * The error text to display when the date in the field is invalid (defaults to
44877 * '{value} is not a valid date - it must be in the format {format}').
44879 invalidText : "{0} is not a valid date - it must be in the format {1}",
44881 * @cfg {String} triggerClass
44882 * An additional CSS class used to style the trigger button. The trigger will always get the
44883 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
44884 * which displays a calendar icon).
44886 triggerClass : 'x-form-date-trigger',
44890 * @cfg {Boolean} useIso
44891 * if enabled, then the date field will use a hidden field to store the
44892 * real value as iso formated date. default (true)
44896 * @cfg {String/Object} autoCreate
44897 * A DomHelper element spec, or true for a default element spec (defaults to
44898 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
44901 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
44904 hiddenField: false,
44906 hideMonthPicker : false,
44908 onRender : function(ct, position)
44910 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
44912 this.el.dom.removeAttribute('name');
44913 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
44915 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
44916 // prevent input submission
44917 this.hiddenName = this.name;
44924 validateValue : function(value)
44926 value = this.formatDate(value);
44927 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
44930 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
44933 var svalue = value;
44934 value = this.parseDate(value);
44936 this.markInvalid(String.format(this.invalidText, svalue, this.format));
44939 var time = value.getTime();
44940 if(this.minValue && time < this.minValue.getTime()){
44941 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
44944 if(this.maxValue && time > this.maxValue.getTime()){
44945 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
44948 /*if(this.disabledDays){
44949 var day = value.getDay();
44950 for(var i = 0; i < this.disabledDays.length; i++) {
44951 if(day === this.disabledDays[i]){
44952 this.markInvalid(this.disabledDaysText);
44958 var fvalue = this.formatDate(value);
44959 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
44960 this.markInvalid(String.format(this.disabledDatesText, fvalue));
44968 // Provides logic to override the default TriggerField.validateBlur which just returns true
44969 validateBlur : function(){
44970 return !this.menu || !this.menu.isVisible();
44974 * Returns the current date value of the date field.
44975 * @return {Date} The date value
44977 getValue : function(){
44981 return this.hiddenField ?
44982 this.hiddenField.value :
44983 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
44987 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
44988 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
44989 * (the default format used is "m/d/y").
44992 //All of these calls set the same date value (May 4, 2006)
44994 //Pass a date object:
44995 var dt = new Date('5/4/06');
44996 monthField.setValue(dt);
44998 //Pass a date string (default format):
44999 monthField.setValue('5/4/06');
45001 //Pass a date string (custom format):
45002 monthField.format = 'Y-m-d';
45003 monthField.setValue('2006-5-4');
45005 * @param {String/Date} date The date or valid date string
45007 setValue : function(date){
45008 Roo.log('month setValue' + date);
45009 // can only be first of month..
45011 var val = this.parseDate(date);
45013 if (this.hiddenField) {
45014 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
45016 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
45017 this.value = this.parseDate(date);
45021 parseDate : function(value){
45022 if(!value || value instanceof Date){
45023 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
45026 var v = Date.parseDate(value, this.format);
45027 if (!v && this.useIso) {
45028 v = Date.parseDate(value, 'Y-m-d');
45032 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
45036 if(!v && this.altFormats){
45037 if(!this.altFormatsArray){
45038 this.altFormatsArray = this.altFormats.split("|");
45040 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
45041 v = Date.parseDate(value, this.altFormatsArray[i]);
45048 formatDate : function(date, fmt){
45049 return (!date || !(date instanceof Date)) ?
45050 date : date.dateFormat(fmt || this.format);
45055 select: function(m, d){
45057 this.fireEvent('select', this, d);
45059 show : function(){ // retain focus styling
45063 this.focus.defer(10, this);
45064 var ml = this.menuListeners;
45065 this.menu.un("select", ml.select, this);
45066 this.menu.un("show", ml.show, this);
45067 this.menu.un("hide", ml.hide, this);
45071 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
45072 onTriggerClick : function(){
45076 if(this.menu == null){
45077 this.menu = new Roo.menu.DateMenu();
45081 Roo.apply(this.menu.picker, {
45083 showClear: this.allowBlank,
45084 minDate : this.minValue,
45085 maxDate : this.maxValue,
45086 disabledDatesRE : this.ddMatch,
45087 disabledDatesText : this.disabledDatesText,
45089 format : this.useIso ? 'Y-m-d' : this.format,
45090 minText : String.format(this.minText, this.formatDate(this.minValue)),
45091 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
45094 this.menu.on(Roo.apply({}, this.menuListeners, {
45102 // hide month picker get's called when we called by 'before hide';
45104 var ignorehide = true;
45105 p.hideMonthPicker = function(disableAnim){
45109 if(this.monthPicker){
45110 Roo.log("hideMonthPicker called");
45111 if(disableAnim === true){
45112 this.monthPicker.hide();
45114 this.monthPicker.slideOut('t', {duration:.2});
45115 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
45116 p.fireEvent("select", this, this.value);
45122 Roo.log('picker set value');
45123 Roo.log(this.getValue());
45124 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
45125 m.show(this.el, 'tl-bl?');
45126 ignorehide = false;
45127 // this will trigger hideMonthPicker..
45130 // hidden the day picker
45131 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
45137 p.showMonthPicker.defer(100, p);
45143 beforeBlur : function(){
45144 var v = this.parseDate(this.getRawValue());
45150 /** @cfg {Boolean} grow @hide */
45151 /** @cfg {Number} growMin @hide */
45152 /** @cfg {Number} growMax @hide */
45159 * Ext JS Library 1.1.1
45160 * Copyright(c) 2006-2007, Ext JS, LLC.
45162 * Originally Released Under LGPL - original licence link has changed is not relivant.
45165 * <script type="text/javascript">
45170 * @class Roo.form.ComboBox
45171 * @extends Roo.form.TriggerField
45172 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
45174 * Create a new ComboBox.
45175 * @param {Object} config Configuration options
45177 Roo.form.ComboBox = function(config){
45178 Roo.form.ComboBox.superclass.constructor.call(this, config);
45182 * Fires when the dropdown list is expanded
45183 * @param {Roo.form.ComboBox} combo This combo box
45188 * Fires when the dropdown list is collapsed
45189 * @param {Roo.form.ComboBox} combo This combo box
45193 * @event beforeselect
45194 * Fires before a list item is selected. Return false to cancel the selection.
45195 * @param {Roo.form.ComboBox} combo This combo box
45196 * @param {Roo.data.Record} record The data record returned from the underlying store
45197 * @param {Number} index The index of the selected item in the dropdown list
45199 'beforeselect' : true,
45202 * Fires when a list item is selected
45203 * @param {Roo.form.ComboBox} combo This combo box
45204 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
45205 * @param {Number} index The index of the selected item in the dropdown list
45209 * @event beforequery
45210 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
45211 * The event object passed has these properties:
45212 * @param {Roo.form.ComboBox} combo This combo box
45213 * @param {String} query The query
45214 * @param {Boolean} forceAll true to force "all" query
45215 * @param {Boolean} cancel true to cancel the query
45216 * @param {Object} e The query event object
45218 'beforequery': true,
45221 * Fires when the 'add' icon is pressed (add a listener to enable add button)
45222 * @param {Roo.form.ComboBox} combo This combo box
45227 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
45228 * @param {Roo.form.ComboBox} combo This combo box
45229 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
45235 if(this.transform){
45236 this.allowDomMove = false;
45237 var s = Roo.getDom(this.transform);
45238 if(!this.hiddenName){
45239 this.hiddenName = s.name;
45242 this.mode = 'local';
45243 var d = [], opts = s.options;
45244 for(var i = 0, len = opts.length;i < len; i++){
45246 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
45248 this.value = value;
45250 d.push([value, o.text]);
45252 this.store = new Roo.data.SimpleStore({
45254 fields: ['value', 'text'],
45257 this.valueField = 'value';
45258 this.displayField = 'text';
45260 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
45261 if(!this.lazyRender){
45262 this.target = true;
45263 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
45264 s.parentNode.removeChild(s); // remove it
45265 this.render(this.el.parentNode);
45267 s.parentNode.removeChild(s); // remove it
45272 this.store = Roo.factory(this.store, Roo.data);
45275 this.selectedIndex = -1;
45276 if(this.mode == 'local'){
45277 if(config.queryDelay === undefined){
45278 this.queryDelay = 10;
45280 if(config.minChars === undefined){
45286 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
45288 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
45291 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
45292 * rendering into an Roo.Editor, defaults to false)
45295 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
45296 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
45299 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
45302 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
45303 * the dropdown list (defaults to undefined, with no header element)
45307 * @cfg {String/Roo.Template} tpl The template to use to render the output
45311 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
45313 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
45315 listWidth: undefined,
45317 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
45318 * mode = 'remote' or 'text' if mode = 'local')
45320 displayField: undefined,
45322 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
45323 * mode = 'remote' or 'value' if mode = 'local').
45324 * Note: use of a valueField requires the user make a selection
45325 * in order for a value to be mapped.
45327 valueField: undefined,
45331 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
45332 * field's data value (defaults to the underlying DOM element's name)
45334 hiddenName: undefined,
45336 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
45340 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
45342 selectedClass: 'x-combo-selected',
45344 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
45345 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
45346 * which displays a downward arrow icon).
45348 triggerClass : 'x-form-arrow-trigger',
45350 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
45354 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
45355 * anchor positions (defaults to 'tl-bl')
45357 listAlign: 'tl-bl?',
45359 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
45363 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
45364 * query specified by the allQuery config option (defaults to 'query')
45366 triggerAction: 'query',
45368 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
45369 * (defaults to 4, does not apply if editable = false)
45373 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
45374 * delay (typeAheadDelay) if it matches a known value (defaults to false)
45378 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
45379 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
45383 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
45384 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
45388 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
45389 * when editable = true (defaults to false)
45391 selectOnFocus:false,
45393 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
45395 queryParam: 'query',
45397 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
45398 * when mode = 'remote' (defaults to 'Loading...')
45400 loadingText: 'Loading...',
45402 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
45406 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
45410 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
45411 * traditional select (defaults to true)
45415 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
45419 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
45423 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
45424 * listWidth has a higher value)
45428 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
45429 * allow the user to set arbitrary text into the field (defaults to false)
45431 forceSelection:false,
45433 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
45434 * if typeAhead = true (defaults to 250)
45436 typeAheadDelay : 250,
45438 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
45439 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
45441 valueNotFoundText : undefined,
45443 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
45445 blockFocus : false,
45448 * @cfg {Boolean} disableClear Disable showing of clear button.
45450 disableClear : false,
45452 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
45454 alwaysQuery : false,
45460 // element that contains real text value.. (when hidden is used..)
45463 onRender : function(ct, position){
45464 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
45465 if(this.hiddenName){
45466 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
45468 this.hiddenField.value =
45469 this.hiddenValue !== undefined ? this.hiddenValue :
45470 this.value !== undefined ? this.value : '';
45472 // prevent input submission
45473 this.el.dom.removeAttribute('name');
45478 this.el.dom.setAttribute('autocomplete', 'off');
45481 var cls = 'x-combo-list';
45483 this.list = new Roo.Layer({
45484 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
45487 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
45488 this.list.setWidth(lw);
45489 this.list.swallowEvent('mousewheel');
45490 this.assetHeight = 0;
45493 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
45494 this.assetHeight += this.header.getHeight();
45497 this.innerList = this.list.createChild({cls:cls+'-inner'});
45498 this.innerList.on('mouseover', this.onViewOver, this);
45499 this.innerList.on('mousemove', this.onViewMove, this);
45500 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
45502 if(this.allowBlank && !this.pageSize && !this.disableClear){
45503 this.footer = this.list.createChild({cls:cls+'-ft'});
45504 this.pageTb = new Roo.Toolbar(this.footer);
45508 this.footer = this.list.createChild({cls:cls+'-ft'});
45509 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
45510 {pageSize: this.pageSize});
45514 if (this.pageTb && this.allowBlank && !this.disableClear) {
45516 this.pageTb.add(new Roo.Toolbar.Fill(), {
45517 cls: 'x-btn-icon x-btn-clear',
45519 handler: function()
45522 _this.clearValue();
45523 _this.onSelect(false, -1);
45528 this.assetHeight += this.footer.getHeight();
45533 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
45536 this.view = new Roo.View(this.innerList, this.tpl, {
45537 singleSelect:true, store: this.store, selectedClass: this.selectedClass
45540 this.view.on('click', this.onViewClick, this);
45542 this.store.on('beforeload', this.onBeforeLoad, this);
45543 this.store.on('load', this.onLoad, this);
45544 this.store.on('loadexception', this.onLoadException, this);
45546 if(this.resizable){
45547 this.resizer = new Roo.Resizable(this.list, {
45548 pinned:true, handles:'se'
45550 this.resizer.on('resize', function(r, w, h){
45551 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
45552 this.listWidth = w;
45553 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
45554 this.restrictHeight();
45556 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
45558 if(!this.editable){
45559 this.editable = true;
45560 this.setEditable(false);
45564 if (typeof(this.events.add.listeners) != 'undefined') {
45566 this.addicon = this.wrap.createChild(
45567 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
45569 this.addicon.on('click', function(e) {
45570 this.fireEvent('add', this);
45573 if (typeof(this.events.edit.listeners) != 'undefined') {
45575 this.editicon = this.wrap.createChild(
45576 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
45577 if (this.addicon) {
45578 this.editicon.setStyle('margin-left', '40px');
45580 this.editicon.on('click', function(e) {
45582 // we fire even if inothing is selected..
45583 this.fireEvent('edit', this, this.lastData );
45593 initEvents : function(){
45594 Roo.form.ComboBox.superclass.initEvents.call(this);
45596 this.keyNav = new Roo.KeyNav(this.el, {
45597 "up" : function(e){
45598 this.inKeyMode = true;
45602 "down" : function(e){
45603 if(!this.isExpanded()){
45604 this.onTriggerClick();
45606 this.inKeyMode = true;
45611 "enter" : function(e){
45612 this.onViewClick();
45616 "esc" : function(e){
45620 "tab" : function(e){
45621 this.onViewClick(false);
45622 this.fireEvent("specialkey", this, e);
45628 doRelay : function(foo, bar, hname){
45629 if(hname == 'down' || this.scope.isExpanded()){
45630 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45637 this.queryDelay = Math.max(this.queryDelay || 10,
45638 this.mode == 'local' ? 10 : 250);
45639 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
45640 if(this.typeAhead){
45641 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
45643 if(this.editable !== false){
45644 this.el.on("keyup", this.onKeyUp, this);
45646 if(this.forceSelection){
45647 this.on('blur', this.doForce, this);
45651 onDestroy : function(){
45653 this.view.setStore(null);
45654 this.view.el.removeAllListeners();
45655 this.view.el.remove();
45656 this.view.purgeListeners();
45659 this.list.destroy();
45662 this.store.un('beforeload', this.onBeforeLoad, this);
45663 this.store.un('load', this.onLoad, this);
45664 this.store.un('loadexception', this.onLoadException, this);
45666 Roo.form.ComboBox.superclass.onDestroy.call(this);
45670 fireKey : function(e){
45671 if(e.isNavKeyPress() && !this.list.isVisible()){
45672 this.fireEvent("specialkey", this, e);
45677 onResize: function(w, h){
45678 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
45680 if(typeof w != 'number'){
45681 // we do not handle it!?!?
45684 var tw = this.trigger.getWidth();
45685 tw += this.addicon ? this.addicon.getWidth() : 0;
45686 tw += this.editicon ? this.editicon.getWidth() : 0;
45688 this.el.setWidth( this.adjustWidth('input', x));
45690 this.trigger.setStyle('left', x+'px');
45692 if(this.list && this.listWidth === undefined){
45693 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
45694 this.list.setWidth(lw);
45695 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
45703 * Allow or prevent the user from directly editing the field text. If false is passed,
45704 * the user will only be able to select from the items defined in the dropdown list. This method
45705 * is the runtime equivalent of setting the 'editable' config option at config time.
45706 * @param {Boolean} value True to allow the user to directly edit the field text
45708 setEditable : function(value){
45709 if(value == this.editable){
45712 this.editable = value;
45714 this.el.dom.setAttribute('readOnly', true);
45715 this.el.on('mousedown', this.onTriggerClick, this);
45716 this.el.addClass('x-combo-noedit');
45718 this.el.dom.setAttribute('readOnly', false);
45719 this.el.un('mousedown', this.onTriggerClick, this);
45720 this.el.removeClass('x-combo-noedit');
45725 onBeforeLoad : function(){
45726 if(!this.hasFocus){
45729 this.innerList.update(this.loadingText ?
45730 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
45731 this.restrictHeight();
45732 this.selectedIndex = -1;
45736 onLoad : function(){
45737 if(!this.hasFocus){
45740 if(this.store.getCount() > 0){
45742 this.restrictHeight();
45743 if(this.lastQuery == this.allQuery){
45745 this.el.dom.select();
45747 if(!this.selectByValue(this.value, true)){
45748 this.select(0, true);
45752 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
45753 this.taTask.delay(this.typeAheadDelay);
45757 this.onEmptyResults();
45762 onLoadException : function()
45765 Roo.log(this.store.reader.jsonData);
45766 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
45767 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
45773 onTypeAhead : function(){
45774 if(this.store.getCount() > 0){
45775 var r = this.store.getAt(0);
45776 var newValue = r.data[this.displayField];
45777 var len = newValue.length;
45778 var selStart = this.getRawValue().length;
45779 if(selStart != len){
45780 this.setRawValue(newValue);
45781 this.selectText(selStart, newValue.length);
45787 onSelect : function(record, index){
45788 if(this.fireEvent('beforeselect', this, record, index) !== false){
45789 this.setFromData(index > -1 ? record.data : false);
45791 this.fireEvent('select', this, record, index);
45796 * Returns the currently selected field value or empty string if no value is set.
45797 * @return {String} value The selected value
45799 getValue : function(){
45800 if(this.valueField){
45801 return typeof this.value != 'undefined' ? this.value : '';
45803 return Roo.form.ComboBox.superclass.getValue.call(this);
45807 * Clears any text/value currently set in the field
45809 clearValue : function(){
45810 if(this.hiddenField){
45811 this.hiddenField.value = '';
45814 this.setRawValue('');
45815 this.lastSelectionText = '';
45820 * Sets the specified value into the field. If the value finds a match, the corresponding record text
45821 * will be displayed in the field. If the value does not match the data value of an existing item,
45822 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
45823 * Otherwise the field will be blank (although the value will still be set).
45824 * @param {String} value The value to match
45826 setValue : function(v){
45828 if(this.valueField){
45829 var r = this.findRecord(this.valueField, v);
45831 text = r.data[this.displayField];
45832 }else if(this.valueNotFoundText !== undefined){
45833 text = this.valueNotFoundText;
45836 this.lastSelectionText = text;
45837 if(this.hiddenField){
45838 this.hiddenField.value = v;
45840 Roo.form.ComboBox.superclass.setValue.call(this, text);
45844 * @property {Object} the last set data for the element
45849 * Sets the value of the field based on a object which is related to the record format for the store.
45850 * @param {Object} value the value to set as. or false on reset?
45852 setFromData : function(o){
45853 var dv = ''; // display value
45854 var vv = ''; // value value..
45856 if (this.displayField) {
45857 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
45859 // this is an error condition!!!
45860 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
45863 if(this.valueField){
45864 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
45866 if(this.hiddenField){
45867 this.hiddenField.value = vv;
45869 this.lastSelectionText = dv;
45870 Roo.form.ComboBox.superclass.setValue.call(this, dv);
45874 // no hidden field.. - we store the value in 'value', but still display
45875 // display field!!!!
45876 this.lastSelectionText = dv;
45877 Roo.form.ComboBox.superclass.setValue.call(this, dv);
45883 reset : function(){
45884 // overridden so that last data is reset..
45885 this.setValue(this.resetValue);
45886 this.clearInvalid();
45887 this.lastData = false;
45889 this.view.clearSelections();
45893 findRecord : function(prop, value){
45895 if(this.store.getCount() > 0){
45896 this.store.each(function(r){
45897 if(r.data[prop] == value){
45907 getName: function()
45909 // returns hidden if it's set..
45910 if (!this.rendered) {return ''};
45911 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
45915 onViewMove : function(e, t){
45916 this.inKeyMode = false;
45920 onViewOver : function(e, t){
45921 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
45924 var item = this.view.findItemFromChild(t);
45926 var index = this.view.indexOf(item);
45927 this.select(index, false);
45932 onViewClick : function(doFocus)
45934 var index = this.view.getSelectedIndexes()[0];
45935 var r = this.store.getAt(index);
45937 this.onSelect(r, index);
45939 if(doFocus !== false && !this.blockFocus){
45945 restrictHeight : function(){
45946 this.innerList.dom.style.height = '';
45947 var inner = this.innerList.dom;
45948 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
45949 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
45950 this.list.beginUpdate();
45951 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
45952 this.list.alignTo(this.el, this.listAlign);
45953 this.list.endUpdate();
45957 onEmptyResults : function(){
45962 * Returns true if the dropdown list is expanded, else false.
45964 isExpanded : function(){
45965 return this.list.isVisible();
45969 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
45970 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
45971 * @param {String} value The data value of the item to select
45972 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
45973 * selected item if it is not currently in view (defaults to true)
45974 * @return {Boolean} True if the value matched an item in the list, else false
45976 selectByValue : function(v, scrollIntoView){
45977 if(v !== undefined && v !== null){
45978 var r = this.findRecord(this.valueField || this.displayField, v);
45980 this.select(this.store.indexOf(r), scrollIntoView);
45988 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
45989 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
45990 * @param {Number} index The zero-based index of the list item to select
45991 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
45992 * selected item if it is not currently in view (defaults to true)
45994 select : function(index, scrollIntoView){
45995 this.selectedIndex = index;
45996 this.view.select(index);
45997 if(scrollIntoView !== false){
45998 var el = this.view.getNode(index);
46000 this.innerList.scrollChildIntoView(el, false);
46006 selectNext : function(){
46007 var ct = this.store.getCount();
46009 if(this.selectedIndex == -1){
46011 }else if(this.selectedIndex < ct-1){
46012 this.select(this.selectedIndex+1);
46018 selectPrev : function(){
46019 var ct = this.store.getCount();
46021 if(this.selectedIndex == -1){
46023 }else if(this.selectedIndex != 0){
46024 this.select(this.selectedIndex-1);
46030 onKeyUp : function(e){
46031 if(this.editable !== false && !e.isSpecialKey()){
46032 this.lastKey = e.getKey();
46033 this.dqTask.delay(this.queryDelay);
46038 validateBlur : function(){
46039 return !this.list || !this.list.isVisible();
46043 initQuery : function(){
46044 this.doQuery(this.getRawValue());
46048 doForce : function(){
46049 if(this.el.dom.value.length > 0){
46050 this.el.dom.value =
46051 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
46057 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
46058 * query allowing the query action to be canceled if needed.
46059 * @param {String} query The SQL query to execute
46060 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
46061 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
46062 * saved in the current store (defaults to false)
46064 doQuery : function(q, forceAll){
46065 if(q === undefined || q === null){
46070 forceAll: forceAll,
46074 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
46078 forceAll = qe.forceAll;
46079 if(forceAll === true || (q.length >= this.minChars)){
46080 if(this.lastQuery != q || this.alwaysQuery){
46081 this.lastQuery = q;
46082 if(this.mode == 'local'){
46083 this.selectedIndex = -1;
46085 this.store.clearFilter();
46087 this.store.filter(this.displayField, q);
46091 this.store.baseParams[this.queryParam] = q;
46093 params: this.getParams(q)
46098 this.selectedIndex = -1;
46105 getParams : function(q){
46107 //p[this.queryParam] = q;
46110 p.limit = this.pageSize;
46116 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
46118 collapse : function(){
46119 if(!this.isExpanded()){
46123 Roo.get(document).un('mousedown', this.collapseIf, this);
46124 Roo.get(document).un('mousewheel', this.collapseIf, this);
46125 if (!this.editable) {
46126 Roo.get(document).un('keydown', this.listKeyPress, this);
46128 this.fireEvent('collapse', this);
46132 collapseIf : function(e){
46133 if(!e.within(this.wrap) && !e.within(this.list)){
46139 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
46141 expand : function(){
46142 if(this.isExpanded() || !this.hasFocus){
46145 this.list.alignTo(this.el, this.listAlign);
46147 Roo.get(document).on('mousedown', this.collapseIf, this);
46148 Roo.get(document).on('mousewheel', this.collapseIf, this);
46149 if (!this.editable) {
46150 Roo.get(document).on('keydown', this.listKeyPress, this);
46153 this.fireEvent('expand', this);
46157 // Implements the default empty TriggerField.onTriggerClick function
46158 onTriggerClick : function(){
46162 if(this.isExpanded()){
46164 if (!this.blockFocus) {
46169 this.hasFocus = true;
46170 if(this.triggerAction == 'all') {
46171 this.doQuery(this.allQuery, true);
46173 this.doQuery(this.getRawValue());
46175 if (!this.blockFocus) {
46180 listKeyPress : function(e)
46182 //Roo.log('listkeypress');
46183 // scroll to first matching element based on key pres..
46184 if (e.isSpecialKey()) {
46187 var k = String.fromCharCode(e.getKey()).toUpperCase();
46190 var csel = this.view.getSelectedNodes();
46191 var cselitem = false;
46193 var ix = this.view.indexOf(csel[0]);
46194 cselitem = this.store.getAt(ix);
46195 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
46201 this.store.each(function(v) {
46203 // start at existing selection.
46204 if (cselitem.id == v.id) {
46210 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
46211 match = this.store.indexOf(v);
46216 if (match === false) {
46217 return true; // no more action?
46220 this.view.select(match);
46221 var sn = Roo.get(this.view.getSelectedNodes()[0]);
46222 sn.scrollIntoView(sn.dom.parentNode, false);
46226 * @cfg {Boolean} grow
46230 * @cfg {Number} growMin
46234 * @cfg {Number} growMax
46242 * Copyright(c) 2010-2012, Roo J Solutions Limited
46249 * @class Roo.form.ComboBoxArray
46250 * @extends Roo.form.TextField
46251 * A facebook style adder... for lists of email / people / countries etc...
46252 * pick multiple items from a combo box, and shows each one.
46254 * Fred [x] Brian [x] [Pick another |v]
46257 * For this to work: it needs various extra information
46258 * - normal combo problay has
46260 * + displayField, valueField
46262 * For our purpose...
46265 * If we change from 'extends' to wrapping...
46272 * Create a new ComboBoxArray.
46273 * @param {Object} config Configuration options
46277 Roo.form.ComboBoxArray = function(config)
46281 * @event beforeremove
46282 * Fires before remove the value from the list
46283 * @param {Roo.form.ComboBoxArray} _self This combo box array
46284 * @param {Roo.form.ComboBoxArray.Item} item removed item
46286 'beforeremove' : true,
46289 * Fires when remove the value from the list
46290 * @param {Roo.form.ComboBoxArray} _self This combo box array
46291 * @param {Roo.form.ComboBoxArray.Item} item removed item
46298 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
46300 this.items = new Roo.util.MixedCollection(false);
46302 // construct the child combo...
46312 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
46315 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
46320 // behavies liek a hiddne field
46321 inputType: 'hidden',
46323 * @cfg {Number} width The width of the box that displays the selected element
46330 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
46334 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
46336 hiddenName : false,
46339 // private the array of items that are displayed..
46341 // private - the hidden field el.
46343 // private - the filed el..
46346 //validateValue : function() { return true; }, // all values are ok!
46347 //onAddClick: function() { },
46349 onRender : function(ct, position)
46352 // create the standard hidden element
46353 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
46356 // give fake names to child combo;
46357 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
46358 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
46360 this.combo = Roo.factory(this.combo, Roo.form);
46361 this.combo.onRender(ct, position);
46362 if (typeof(this.combo.width) != 'undefined') {
46363 this.combo.onResize(this.combo.width,0);
46366 this.combo.initEvents();
46368 // assigned so form know we need to do this..
46369 this.store = this.combo.store;
46370 this.valueField = this.combo.valueField;
46371 this.displayField = this.combo.displayField ;
46374 this.combo.wrap.addClass('x-cbarray-grp');
46376 var cbwrap = this.combo.wrap.createChild(
46377 {tag: 'div', cls: 'x-cbarray-cb'},
46382 this.hiddenEl = this.combo.wrap.createChild({
46383 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
46385 this.el = this.combo.wrap.createChild({
46386 tag: 'input', type:'hidden' , name: this.name, value : ''
46388 // this.el.dom.removeAttribute("name");
46391 this.outerWrap = this.combo.wrap;
46392 this.wrap = cbwrap;
46394 this.outerWrap.setWidth(this.width);
46395 this.outerWrap.dom.removeChild(this.el.dom);
46397 this.wrap.dom.appendChild(this.el.dom);
46398 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
46399 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
46401 this.combo.trigger.setStyle('position','relative');
46402 this.combo.trigger.setStyle('left', '0px');
46403 this.combo.trigger.setStyle('top', '2px');
46405 this.combo.el.setStyle('vertical-align', 'text-bottom');
46407 //this.trigger.setStyle('vertical-align', 'top');
46409 // this should use the code from combo really... on('add' ....)
46413 this.adder = this.outerWrap.createChild(
46414 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
46416 this.adder.on('click', function(e) {
46417 _t.fireEvent('adderclick', this, e);
46421 //this.adder.on('click', this.onAddClick, _t);
46424 this.combo.on('select', function(cb, rec, ix) {
46425 this.addItem(rec.data);
46428 cb.el.dom.value = '';
46429 //cb.lastData = rec.data;
46438 getName: function()
46440 // returns hidden if it's set..
46441 if (!this.rendered) {return ''};
46442 return this.hiddenName ? this.hiddenName : this.name;
46447 onResize: function(w, h){
46450 // not sure if this is needed..
46451 //this.combo.onResize(w,h);
46453 if(typeof w != 'number'){
46454 // we do not handle it!?!?
46457 var tw = this.combo.trigger.getWidth();
46458 tw += this.addicon ? this.addicon.getWidth() : 0;
46459 tw += this.editicon ? this.editicon.getWidth() : 0;
46461 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
46463 this.combo.trigger.setStyle('left', '0px');
46465 if(this.list && this.listWidth === undefined){
46466 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
46467 this.list.setWidth(lw);
46468 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
46475 addItem: function(rec)
46477 var valueField = this.combo.valueField;
46478 var displayField = this.combo.displayField;
46479 if (this.items.indexOfKey(rec[valueField]) > -1) {
46480 //console.log("GOT " + rec.data.id);
46484 var x = new Roo.form.ComboBoxArray.Item({
46485 //id : rec[this.idField],
46487 displayField : displayField ,
46488 tipField : displayField ,
46492 this.items.add(rec[valueField],x);
46493 // add it before the element..
46494 this.updateHiddenEl();
46495 x.render(this.outerWrap, this.wrap.dom);
46496 // add the image handler..
46499 updateHiddenEl : function()
46502 if (!this.hiddenEl) {
46506 var idField = this.combo.valueField;
46508 this.items.each(function(f) {
46509 ar.push(f.data[idField]);
46512 this.hiddenEl.dom.value = ar.join(',');
46518 this.items.clear();
46520 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
46524 this.el.dom.value = '';
46525 if (this.hiddenEl) {
46526 this.hiddenEl.dom.value = '';
46530 getValue: function()
46532 return this.hiddenEl ? this.hiddenEl.dom.value : '';
46534 setValue: function(v) // not a valid action - must use addItems..
46541 if (this.store.isLocal && (typeof(v) == 'string')) {
46542 // then we can use the store to find the values..
46543 // comma seperated at present.. this needs to allow JSON based encoding..
46544 this.hiddenEl.value = v;
46546 Roo.each(v.split(','), function(k) {
46547 Roo.log("CHECK " + this.valueField + ',' + k);
46548 var li = this.store.query(this.valueField, k);
46553 add[this.valueField] = k;
46554 add[this.displayField] = li.item(0).data[this.displayField];
46560 if (typeof(v) == 'object' ) {
46561 // then let's assume it's an array of objects..
46562 Roo.each(v, function(l) {
46570 setFromData: function(v)
46572 // this recieves an object, if setValues is called.
46574 this.el.dom.value = v[this.displayField];
46575 this.hiddenEl.dom.value = v[this.valueField];
46576 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
46579 var kv = v[this.valueField];
46580 var dv = v[this.displayField];
46581 kv = typeof(kv) != 'string' ? '' : kv;
46582 dv = typeof(dv) != 'string' ? '' : dv;
46585 var keys = kv.split(',');
46586 var display = dv.split(',');
46587 for (var i = 0 ; i < keys.length; i++) {
46590 add[this.valueField] = keys[i];
46591 add[this.displayField] = display[i];
46599 * Validates the combox array value
46600 * @return {Boolean} True if the value is valid, else false
46602 validate : function(){
46603 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
46604 this.clearInvalid();
46610 validateValue : function(value){
46611 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
46619 isDirty : function() {
46620 if(this.disabled) {
46625 var d = Roo.decode(String(this.originalValue));
46627 return String(this.getValue()) !== String(this.originalValue);
46630 var originalValue = [];
46632 for (var i = 0; i < d.length; i++){
46633 originalValue.push(d[i][this.valueField]);
46636 return String(this.getValue()) !== String(originalValue.join(','));
46645 * @class Roo.form.ComboBoxArray.Item
46646 * @extends Roo.BoxComponent
46647 * A selected item in the list
46648 * Fred [x] Brian [x] [Pick another |v]
46651 * Create a new item.
46652 * @param {Object} config Configuration options
46655 Roo.form.ComboBoxArray.Item = function(config) {
46656 config.id = Roo.id();
46657 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
46660 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
46663 displayField : false,
46667 defaultAutoCreate : {
46669 cls: 'x-cbarray-item',
46676 src : Roo.BLANK_IMAGE_URL ,
46684 onRender : function(ct, position)
46686 Roo.form.Field.superclass.onRender.call(this, ct, position);
46689 var cfg = this.getAutoCreate();
46690 this.el = ct.createChild(cfg, position);
46693 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
46695 this.el.child('div').dom.innerHTML = this.cb.renderer ?
46696 this.cb.renderer(this.data) :
46697 String.format('{0}',this.data[this.displayField]);
46700 this.el.child('div').dom.setAttribute('qtip',
46701 String.format('{0}',this.data[this.tipField])
46704 this.el.child('img').on('click', this.remove, this);
46708 remove : function()
46710 if(this.cb.disabled){
46714 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
46715 this.cb.items.remove(this);
46716 this.el.child('img').un('click', this.remove, this);
46718 this.cb.updateHiddenEl();
46720 this.cb.fireEvent('remove', this.cb, this);
46726 * Ext JS Library 1.1.1
46727 * Copyright(c) 2006-2007, Ext JS, LLC.
46729 * Originally Released Under LGPL - original licence link has changed is not relivant.
46732 * <script type="text/javascript">
46735 * @class Roo.form.Checkbox
46736 * @extends Roo.form.Field
46737 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
46739 * Creates a new Checkbox
46740 * @param {Object} config Configuration options
46742 Roo.form.Checkbox = function(config){
46743 Roo.form.Checkbox.superclass.constructor.call(this, config);
46747 * Fires when the checkbox is checked or unchecked.
46748 * @param {Roo.form.Checkbox} this This checkbox
46749 * @param {Boolean} checked The new checked value
46755 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
46757 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46759 focusClass : undefined,
46761 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46763 fieldClass: "x-form-field",
46765 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
46769 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46770 * {tag: "input", type: "checkbox", autocomplete: "off"})
46772 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46774 * @cfg {String} boxLabel The text that appears beside the checkbox
46778 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
46782 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
46784 valueOff: '0', // value when not checked..
46786 actionMode : 'viewEl',
46789 itemCls : 'x-menu-check-item x-form-item',
46790 groupClass : 'x-menu-group-item',
46791 inputType : 'hidden',
46794 inSetChecked: false, // check that we are not calling self...
46796 inputElement: false, // real input element?
46797 basedOn: false, // ????
46799 isFormField: true, // not sure where this is needed!!!!
46801 onResize : function(){
46802 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46803 if(!this.boxLabel){
46804 this.el.alignTo(this.wrap, 'c-c');
46808 initEvents : function(){
46809 Roo.form.Checkbox.superclass.initEvents.call(this);
46810 this.el.on("click", this.onClick, this);
46811 this.el.on("change", this.onClick, this);
46815 getResizeEl : function(){
46819 getPositionEl : function(){
46824 onRender : function(ct, position){
46825 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46827 if(this.inputValue !== undefined){
46828 this.el.dom.value = this.inputValue;
46831 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
46832 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
46833 var viewEl = this.wrap.createChild({
46834 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
46835 this.viewEl = viewEl;
46836 this.wrap.on('click', this.onClick, this);
46838 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46839 this.el.on('propertychange', this.setFromHidden, this); //ie
46844 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
46845 // viewEl.on('click', this.onClick, this);
46847 //if(this.checked){
46848 this.setChecked(this.checked);
46850 //this.checked = this.el.dom;
46856 initValue : Roo.emptyFn,
46859 * Returns the checked state of the checkbox.
46860 * @return {Boolean} True if checked, else false
46862 getValue : function(){
46864 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
46866 return this.valueOff;
46871 onClick : function(){
46872 if (this.disabled) {
46875 this.setChecked(!this.checked);
46877 //if(this.el.dom.checked != this.checked){
46878 // this.setValue(this.el.dom.checked);
46883 * Sets the checked state of the checkbox.
46884 * On is always based on a string comparison between inputValue and the param.
46885 * @param {Boolean/String} value - the value to set
46886 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46888 setValue : function(v,suppressEvent){
46891 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
46892 //if(this.el && this.el.dom){
46893 // this.el.dom.checked = this.checked;
46894 // this.el.dom.defaultChecked = this.checked;
46896 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
46897 //this.fireEvent("check", this, this.checked);
46900 setChecked : function(state,suppressEvent)
46902 if (this.inSetChecked) {
46903 this.checked = state;
46909 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
46911 this.checked = state;
46912 if(suppressEvent !== true){
46913 this.fireEvent('check', this, state);
46915 this.inSetChecked = true;
46916 this.el.dom.value = state ? this.inputValue : this.valueOff;
46917 this.inSetChecked = false;
46920 // handle setting of hidden value by some other method!!?!?
46921 setFromHidden: function()
46926 //console.log("SET FROM HIDDEN");
46927 //alert('setFrom hidden');
46928 this.setValue(this.el.dom.value);
46931 onDestroy : function()
46934 Roo.get(this.viewEl).remove();
46937 Roo.form.Checkbox.superclass.onDestroy.call(this);
46940 setBoxLabel : function(str)
46942 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
46947 * Ext JS Library 1.1.1
46948 * Copyright(c) 2006-2007, Ext JS, LLC.
46950 * Originally Released Under LGPL - original licence link has changed is not relivant.
46953 * <script type="text/javascript">
46957 * @class Roo.form.Radio
46958 * @extends Roo.form.Checkbox
46959 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
46960 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
46962 * Creates a new Radio
46963 * @param {Object} config Configuration options
46965 Roo.form.Radio = function(){
46966 Roo.form.Radio.superclass.constructor.apply(this, arguments);
46968 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
46969 inputType: 'radio',
46972 * If this radio is part of a group, it will return the selected value
46975 getGroupValue : function(){
46976 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
46980 onRender : function(ct, position){
46981 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46983 if(this.inputValue !== undefined){
46984 this.el.dom.value = this.inputValue;
46987 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
46988 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
46989 //var viewEl = this.wrap.createChild({
46990 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
46991 //this.viewEl = viewEl;
46992 //this.wrap.on('click', this.onClick, this);
46994 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46995 //this.el.on('propertychange', this.setFromHidden, this); //ie
47000 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
47001 // viewEl.on('click', this.onClick, this);
47004 this.el.dom.checked = 'checked' ;
47010 });//<script type="text/javascript">
47013 * Based Ext JS Library 1.1.1
47014 * Copyright(c) 2006-2007, Ext JS, LLC.
47020 * @class Roo.HtmlEditorCore
47021 * @extends Roo.Component
47022 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
47024 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
47027 Roo.HtmlEditorCore = function(config){
47030 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
47035 * @event initialize
47036 * Fires when the editor is fully initialized (including the iframe)
47037 * @param {Roo.HtmlEditorCore} this
47042 * Fires when the editor is first receives the focus. Any insertion must wait
47043 * until after this event.
47044 * @param {Roo.HtmlEditorCore} this
47048 * @event beforesync
47049 * Fires before the textarea is updated with content from the editor iframe. Return false
47050 * to cancel the sync.
47051 * @param {Roo.HtmlEditorCore} this
47052 * @param {String} html
47056 * @event beforepush
47057 * Fires before the iframe editor is updated with content from the textarea. Return false
47058 * to cancel the push.
47059 * @param {Roo.HtmlEditorCore} this
47060 * @param {String} html
47065 * Fires when the textarea is updated with content from the editor iframe.
47066 * @param {Roo.HtmlEditorCore} this
47067 * @param {String} html
47072 * Fires when the iframe editor is updated with content from the textarea.
47073 * @param {Roo.HtmlEditorCore} this
47074 * @param {String} html
47079 * @event editorevent
47080 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
47081 * @param {Roo.HtmlEditorCore} this
47087 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
47089 // defaults : white / black...
47090 this.applyBlacklists();
47097 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
47101 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
47107 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
47112 * @cfg {Number} height (in pixels)
47116 * @cfg {Number} width (in pixels)
47121 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
47124 stylesheets: false,
47129 // private properties
47130 validationEvent : false,
47132 initialized : false,
47134 sourceEditMode : false,
47135 onFocus : Roo.emptyFn,
47137 hideMode:'offsets',
47141 // blacklist + whitelisted elements..
47148 * Protected method that will not generally be called directly. It
47149 * is called when the editor initializes the iframe with HTML contents. Override this method if you
47150 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
47152 getDocMarkup : function(){
47156 // inherit styels from page...??
47157 if (this.stylesheets === false) {
47159 Roo.get(document.head).select('style').each(function(node) {
47160 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
47163 Roo.get(document.head).select('link').each(function(node) {
47164 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
47167 } else if (!this.stylesheets.length) {
47169 st = '<style type="text/css">' +
47170 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
47176 st += '<style type="text/css">' +
47177 'IMG { cursor: pointer } ' +
47181 return '<html><head>' + st +
47182 //<style type="text/css">' +
47183 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
47185 ' </head><body class="roo-htmleditor-body"></body></html>';
47189 onRender : function(ct, position)
47192 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
47193 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
47196 this.el.dom.style.border = '0 none';
47197 this.el.dom.setAttribute('tabIndex', -1);
47198 this.el.addClass('x-hidden hide');
47202 if(Roo.isIE){ // fix IE 1px bogus margin
47203 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
47207 this.frameId = Roo.id();
47211 var iframe = this.owner.wrap.createChild({
47213 cls: 'form-control', // bootstrap..
47215 name: this.frameId,
47216 frameBorder : 'no',
47217 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
47222 this.iframe = iframe.dom;
47224 this.assignDocWin();
47226 this.doc.designMode = 'on';
47229 this.doc.write(this.getDocMarkup());
47233 var task = { // must defer to wait for browser to be ready
47235 //console.log("run task?" + this.doc.readyState);
47236 this.assignDocWin();
47237 if(this.doc.body || this.doc.readyState == 'complete'){
47239 this.doc.designMode="on";
47243 Roo.TaskMgr.stop(task);
47244 this.initEditor.defer(10, this);
47251 Roo.TaskMgr.start(task);
47256 onResize : function(w, h)
47258 Roo.log('resize: ' +w + ',' + h );
47259 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
47263 if(typeof w == 'number'){
47265 this.iframe.style.width = w + 'px';
47267 if(typeof h == 'number'){
47269 this.iframe.style.height = h + 'px';
47271 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
47278 * Toggles the editor between standard and source edit mode.
47279 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
47281 toggleSourceEdit : function(sourceEditMode){
47283 this.sourceEditMode = sourceEditMode === true;
47285 if(this.sourceEditMode){
47287 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
47290 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
47291 //this.iframe.className = '';
47294 //this.setSize(this.owner.wrap.getSize());
47295 //this.fireEvent('editmodechange', this, this.sourceEditMode);
47302 * Protected method that will not generally be called directly. If you need/want
47303 * custom HTML cleanup, this is the method you should override.
47304 * @param {String} html The HTML to be cleaned
47305 * return {String} The cleaned HTML
47307 cleanHtml : function(html){
47308 html = String(html);
47309 if(html.length > 5){
47310 if(Roo.isSafari){ // strip safari nonsense
47311 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
47314 if(html == ' '){
47321 * HTML Editor -> Textarea
47322 * Protected method that will not generally be called directly. Syncs the contents
47323 * of the editor iframe with the textarea.
47325 syncValue : function(){
47326 if(this.initialized){
47327 var bd = (this.doc.body || this.doc.documentElement);
47328 //this.cleanUpPaste(); -- this is done else where and causes havoc..
47329 var html = bd.innerHTML;
47331 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
47332 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
47334 html = '<div style="'+m[0]+'">' + html + '</div>';
47337 html = this.cleanHtml(html);
47338 // fix up the special chars.. normaly like back quotes in word...
47339 // however we do not want to do this with chinese..
47340 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
47341 var cc = b.charCodeAt();
47343 (cc >= 0x4E00 && cc < 0xA000 ) ||
47344 (cc >= 0x3400 && cc < 0x4E00 ) ||
47345 (cc >= 0xf900 && cc < 0xfb00 )
47351 if(this.owner.fireEvent('beforesync', this, html) !== false){
47352 this.el.dom.value = html;
47353 this.owner.fireEvent('sync', this, html);
47359 * Protected method that will not generally be called directly. Pushes the value of the textarea
47360 * into the iframe editor.
47362 pushValue : function(){
47363 if(this.initialized){
47364 var v = this.el.dom.value.trim();
47366 // if(v.length < 1){
47370 if(this.owner.fireEvent('beforepush', this, v) !== false){
47371 var d = (this.doc.body || this.doc.documentElement);
47373 this.cleanUpPaste();
47374 this.el.dom.value = d.innerHTML;
47375 this.owner.fireEvent('push', this, v);
47381 deferFocus : function(){
47382 this.focus.defer(10, this);
47386 focus : function(){
47387 if(this.win && !this.sourceEditMode){
47394 assignDocWin: function()
47396 var iframe = this.iframe;
47399 this.doc = iframe.contentWindow.document;
47400 this.win = iframe.contentWindow;
47402 // if (!Roo.get(this.frameId)) {
47405 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
47406 // this.win = Roo.get(this.frameId).dom.contentWindow;
47408 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
47412 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
47413 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
47418 initEditor : function(){
47419 //console.log("INIT EDITOR");
47420 this.assignDocWin();
47424 this.doc.designMode="on";
47426 this.doc.write(this.getDocMarkup());
47429 var dbody = (this.doc.body || this.doc.documentElement);
47430 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
47431 // this copies styles from the containing element into thsi one..
47432 // not sure why we need all of this..
47433 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
47435 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
47436 //ss['background-attachment'] = 'fixed'; // w3c
47437 dbody.bgProperties = 'fixed'; // ie
47438 //Roo.DomHelper.applyStyles(dbody, ss);
47439 Roo.EventManager.on(this.doc, {
47440 //'mousedown': this.onEditorEvent,
47441 'mouseup': this.onEditorEvent,
47442 'dblclick': this.onEditorEvent,
47443 'click': this.onEditorEvent,
47444 'keyup': this.onEditorEvent,
47449 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
47451 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
47452 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
47454 this.initialized = true;
47456 this.owner.fireEvent('initialize', this);
47461 onDestroy : function(){
47467 //for (var i =0; i < this.toolbars.length;i++) {
47468 // // fixme - ask toolbars for heights?
47469 // this.toolbars[i].onDestroy();
47472 //this.wrap.dom.innerHTML = '';
47473 //this.wrap.remove();
47478 onFirstFocus : function(){
47480 this.assignDocWin();
47483 this.activated = true;
47486 if(Roo.isGecko){ // prevent silly gecko errors
47488 var s = this.win.getSelection();
47489 if(!s.focusNode || s.focusNode.nodeType != 3){
47490 var r = s.getRangeAt(0);
47491 r.selectNodeContents((this.doc.body || this.doc.documentElement));
47496 this.execCmd('useCSS', true);
47497 this.execCmd('styleWithCSS', false);
47500 this.owner.fireEvent('activate', this);
47504 adjustFont: function(btn){
47505 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
47506 //if(Roo.isSafari){ // safari
47509 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
47510 if(Roo.isSafari){ // safari
47511 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
47512 v = (v < 10) ? 10 : v;
47513 v = (v > 48) ? 48 : v;
47514 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
47519 v = Math.max(1, v+adjust);
47521 this.execCmd('FontSize', v );
47524 onEditorEvent : function(e)
47526 this.owner.fireEvent('editorevent', this, e);
47527 // this.updateToolbar();
47528 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
47531 insertTag : function(tg)
47533 // could be a bit smarter... -> wrap the current selected tRoo..
47534 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
47536 range = this.createRange(this.getSelection());
47537 var wrappingNode = this.doc.createElement(tg.toLowerCase());
47538 wrappingNode.appendChild(range.extractContents());
47539 range.insertNode(wrappingNode);
47546 this.execCmd("formatblock", tg);
47550 insertText : function(txt)
47554 var range = this.createRange();
47555 range.deleteContents();
47556 //alert(Sender.getAttribute('label'));
47558 range.insertNode(this.doc.createTextNode(txt));
47564 * Executes a Midas editor command on the editor document and performs necessary focus and
47565 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
47566 * @param {String} cmd The Midas command
47567 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
47569 relayCmd : function(cmd, value){
47571 this.execCmd(cmd, value);
47572 this.owner.fireEvent('editorevent', this);
47573 //this.updateToolbar();
47574 this.owner.deferFocus();
47578 * Executes a Midas editor command directly on the editor document.
47579 * For visual commands, you should use {@link #relayCmd} instead.
47580 * <b>This should only be called after the editor is initialized.</b>
47581 * @param {String} cmd The Midas command
47582 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
47584 execCmd : function(cmd, value){
47585 this.doc.execCommand(cmd, false, value === undefined ? null : value);
47592 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
47594 * @param {String} text | dom node..
47596 insertAtCursor : function(text)
47601 if(!this.activated){
47607 var r = this.doc.selection.createRange();
47618 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
47622 // from jquery ui (MIT licenced)
47624 var win = this.win;
47626 if (win.getSelection && win.getSelection().getRangeAt) {
47627 range = win.getSelection().getRangeAt(0);
47628 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
47629 range.insertNode(node);
47630 } else if (win.document.selection && win.document.selection.createRange) {
47631 // no firefox support
47632 var txt = typeof(text) == 'string' ? text : text.outerHTML;
47633 win.document.selection.createRange().pasteHTML(txt);
47635 // no firefox support
47636 var txt = typeof(text) == 'string' ? text : text.outerHTML;
47637 this.execCmd('InsertHTML', txt);
47646 mozKeyPress : function(e){
47648 var c = e.getCharCode(), cmd;
47651 c = String.fromCharCode(c).toLowerCase();
47665 this.cleanUpPaste.defer(100, this);
47673 e.preventDefault();
47681 fixKeys : function(){ // load time branching for fastest keydown performance
47683 return function(e){
47684 var k = e.getKey(), r;
47687 r = this.doc.selection.createRange();
47690 r.pasteHTML('    ');
47697 r = this.doc.selection.createRange();
47699 var target = r.parentElement();
47700 if(!target || target.tagName.toLowerCase() != 'li'){
47702 r.pasteHTML('<br />');
47708 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
47709 this.cleanUpPaste.defer(100, this);
47715 }else if(Roo.isOpera){
47716 return function(e){
47717 var k = e.getKey();
47721 this.execCmd('InsertHTML','    ');
47724 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
47725 this.cleanUpPaste.defer(100, this);
47730 }else if(Roo.isSafari){
47731 return function(e){
47732 var k = e.getKey();
47736 this.execCmd('InsertText','\t');
47740 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
47741 this.cleanUpPaste.defer(100, this);
47749 getAllAncestors: function()
47751 var p = this.getSelectedNode();
47754 a.push(p); // push blank onto stack..
47755 p = this.getParentElement();
47759 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
47763 a.push(this.doc.body);
47767 lastSelNode : false,
47770 getSelection : function()
47772 this.assignDocWin();
47773 return Roo.isIE ? this.doc.selection : this.win.getSelection();
47776 getSelectedNode: function()
47778 // this may only work on Gecko!!!
47780 // should we cache this!!!!
47785 var range = this.createRange(this.getSelection()).cloneRange();
47788 var parent = range.parentElement();
47790 var testRange = range.duplicate();
47791 testRange.moveToElementText(parent);
47792 if (testRange.inRange(range)) {
47795 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
47798 parent = parent.parentElement;
47803 // is ancestor a text element.
47804 var ac = range.commonAncestorContainer;
47805 if (ac.nodeType == 3) {
47806 ac = ac.parentNode;
47809 var ar = ac.childNodes;
47812 var other_nodes = [];
47813 var has_other_nodes = false;
47814 for (var i=0;i<ar.length;i++) {
47815 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
47818 // fullly contained node.
47820 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
47825 // probably selected..
47826 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
47827 other_nodes.push(ar[i]);
47831 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
47836 has_other_nodes = true;
47838 if (!nodes.length && other_nodes.length) {
47839 nodes= other_nodes;
47841 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
47847 createRange: function(sel)
47849 // this has strange effects when using with
47850 // top toolbar - not sure if it's a great idea.
47851 //this.editor.contentWindow.focus();
47852 if (typeof sel != "undefined") {
47854 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
47856 return this.doc.createRange();
47859 return this.doc.createRange();
47862 getParentElement: function()
47865 this.assignDocWin();
47866 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
47868 var range = this.createRange(sel);
47871 var p = range.commonAncestorContainer;
47872 while (p.nodeType == 3) { // text node
47883 * Range intersection.. the hard stuff...
47887 * [ -- selected range --- ]
47891 * if end is before start or hits it. fail.
47892 * if start is after end or hits it fail.
47894 * if either hits (but other is outside. - then it's not
47900 // @see http://www.thismuchiknow.co.uk/?p=64.
47901 rangeIntersectsNode : function(range, node)
47903 var nodeRange = node.ownerDocument.createRange();
47905 nodeRange.selectNode(node);
47907 nodeRange.selectNodeContents(node);
47910 var rangeStartRange = range.cloneRange();
47911 rangeStartRange.collapse(true);
47913 var rangeEndRange = range.cloneRange();
47914 rangeEndRange.collapse(false);
47916 var nodeStartRange = nodeRange.cloneRange();
47917 nodeStartRange.collapse(true);
47919 var nodeEndRange = nodeRange.cloneRange();
47920 nodeEndRange.collapse(false);
47922 return rangeStartRange.compareBoundaryPoints(
47923 Range.START_TO_START, nodeEndRange) == -1 &&
47924 rangeEndRange.compareBoundaryPoints(
47925 Range.START_TO_START, nodeStartRange) == 1;
47929 rangeCompareNode : function(range, node)
47931 var nodeRange = node.ownerDocument.createRange();
47933 nodeRange.selectNode(node);
47935 nodeRange.selectNodeContents(node);
47939 range.collapse(true);
47941 nodeRange.collapse(true);
47943 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
47944 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
47946 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
47948 var nodeIsBefore = ss == 1;
47949 var nodeIsAfter = ee == -1;
47951 if (nodeIsBefore && nodeIsAfter) {
47954 if (!nodeIsBefore && nodeIsAfter) {
47955 return 1; //right trailed.
47958 if (nodeIsBefore && !nodeIsAfter) {
47959 return 2; // left trailed.
47965 // private? - in a new class?
47966 cleanUpPaste : function()
47968 // cleans up the whole document..
47969 Roo.log('cleanuppaste');
47971 this.cleanUpChildren(this.doc.body);
47972 var clean = this.cleanWordChars(this.doc.body.innerHTML);
47973 if (clean != this.doc.body.innerHTML) {
47974 this.doc.body.innerHTML = clean;
47979 cleanWordChars : function(input) {// change the chars to hex code
47980 var he = Roo.HtmlEditorCore;
47982 var output = input;
47983 Roo.each(he.swapCodes, function(sw) {
47984 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
47986 output = output.replace(swapper, sw[1]);
47993 cleanUpChildren : function (n)
47995 if (!n.childNodes.length) {
47998 for (var i = n.childNodes.length-1; i > -1 ; i--) {
47999 this.cleanUpChild(n.childNodes[i]);
48006 cleanUpChild : function (node)
48009 //console.log(node);
48010 if (node.nodeName == "#text") {
48011 // clean up silly Windows -- stuff?
48014 if (node.nodeName == "#comment") {
48015 node.parentNode.removeChild(node);
48016 // clean up silly Windows -- stuff?
48019 var lcname = node.tagName.toLowerCase();
48020 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
48021 // whitelist of tags..
48023 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
48025 node.parentNode.removeChild(node);
48030 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
48032 // remove <a name=....> as rendering on yahoo mailer is borked with this.
48033 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
48035 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
48036 // remove_keep_children = true;
48039 if (remove_keep_children) {
48040 this.cleanUpChildren(node);
48041 // inserts everything just before this node...
48042 while (node.childNodes.length) {
48043 var cn = node.childNodes[0];
48044 node.removeChild(cn);
48045 node.parentNode.insertBefore(cn, node);
48047 node.parentNode.removeChild(node);
48051 if (!node.attributes || !node.attributes.length) {
48052 this.cleanUpChildren(node);
48056 function cleanAttr(n,v)
48059 if (v.match(/^\./) || v.match(/^\//)) {
48062 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
48065 if (v.match(/^#/)) {
48068 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
48069 node.removeAttribute(n);
48073 var cwhite = this.cwhite;
48074 var cblack = this.cblack;
48076 function cleanStyle(n,v)
48078 if (v.match(/expression/)) { //XSS?? should we even bother..
48079 node.removeAttribute(n);
48083 var parts = v.split(/;/);
48086 Roo.each(parts, function(p) {
48087 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
48091 var l = p.split(':').shift().replace(/\s+/g,'');
48092 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
48094 if ( cwhite.length && cblack.indexOf(l) > -1) {
48095 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
48096 //node.removeAttribute(n);
48100 // only allow 'c whitelisted system attributes'
48101 if ( cwhite.length && cwhite.indexOf(l) < 0) {
48102 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
48103 //node.removeAttribute(n);
48113 if (clean.length) {
48114 node.setAttribute(n, clean.join(';'));
48116 node.removeAttribute(n);
48122 for (var i = node.attributes.length-1; i > -1 ; i--) {
48123 var a = node.attributes[i];
48126 if (a.name.toLowerCase().substr(0,2)=='on') {
48127 node.removeAttribute(a.name);
48130 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
48131 node.removeAttribute(a.name);
48134 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
48135 cleanAttr(a.name,a.value); // fixme..
48138 if (a.name == 'style') {
48139 cleanStyle(a.name,a.value);
48142 /// clean up MS crap..
48143 // tecnically this should be a list of valid class'es..
48146 if (a.name == 'class') {
48147 if (a.value.match(/^Mso/)) {
48148 node.className = '';
48151 if (a.value.match(/body/)) {
48152 node.className = '';
48163 this.cleanUpChildren(node);
48169 * Clean up MS wordisms...
48171 cleanWord : function(node)
48176 this.cleanWord(this.doc.body);
48179 if (node.nodeName == "#text") {
48180 // clean up silly Windows -- stuff?
48183 if (node.nodeName == "#comment") {
48184 node.parentNode.removeChild(node);
48185 // clean up silly Windows -- stuff?
48189 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
48190 node.parentNode.removeChild(node);
48194 // remove - but keep children..
48195 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
48196 while (node.childNodes.length) {
48197 var cn = node.childNodes[0];
48198 node.removeChild(cn);
48199 node.parentNode.insertBefore(cn, node);
48201 node.parentNode.removeChild(node);
48202 this.iterateChildren(node, this.cleanWord);
48206 if (node.className.length) {
48208 var cn = node.className.split(/\W+/);
48210 Roo.each(cn, function(cls) {
48211 if (cls.match(/Mso[a-zA-Z]+/)) {
48216 node.className = cna.length ? cna.join(' ') : '';
48218 node.removeAttribute("class");
48222 if (node.hasAttribute("lang")) {
48223 node.removeAttribute("lang");
48226 if (node.hasAttribute("style")) {
48228 var styles = node.getAttribute("style").split(";");
48230 Roo.each(styles, function(s) {
48231 if (!s.match(/:/)) {
48234 var kv = s.split(":");
48235 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
48238 // what ever is left... we allow.
48241 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
48242 if (!nstyle.length) {
48243 node.removeAttribute('style');
48246 this.iterateChildren(node, this.cleanWord);
48252 * iterateChildren of a Node, calling fn each time, using this as the scole..
48253 * @param {DomNode} node node to iterate children of.
48254 * @param {Function} fn method of this class to call on each item.
48256 iterateChildren : function(node, fn)
48258 if (!node.childNodes.length) {
48261 for (var i = node.childNodes.length-1; i > -1 ; i--) {
48262 fn.call(this, node.childNodes[i])
48268 * cleanTableWidths.
48270 * Quite often pasting from word etc.. results in tables with column and widths.
48271 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
48274 cleanTableWidths : function(node)
48279 this.cleanTableWidths(this.doc.body);
48284 if (node.nodeName == "#text" || node.nodeName == "#comment") {
48287 Roo.log(node.tagName);
48288 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
48289 this.iterateChildren(node, this.cleanTableWidths);
48292 if (node.hasAttribute('width')) {
48293 node.removeAttribute('width');
48297 if (node.hasAttribute("style")) {
48300 var styles = node.getAttribute("style").split(";");
48302 Roo.each(styles, function(s) {
48303 if (!s.match(/:/)) {
48306 var kv = s.split(":");
48307 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
48310 // what ever is left... we allow.
48313 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
48314 if (!nstyle.length) {
48315 node.removeAttribute('style');
48319 this.iterateChildren(node, this.cleanTableWidths);
48327 domToHTML : function(currentElement, depth, nopadtext) {
48329 depth = depth || 0;
48330 nopadtext = nopadtext || false;
48332 if (!currentElement) {
48333 return this.domToHTML(this.doc.body);
48336 //Roo.log(currentElement);
48338 var allText = false;
48339 var nodeName = currentElement.nodeName;
48340 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
48342 if (nodeName == '#text') {
48344 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
48349 if (nodeName != 'BODY') {
48352 // Prints the node tagName, such as <A>, <IMG>, etc
48355 for(i = 0; i < currentElement.attributes.length;i++) {
48357 var aname = currentElement.attributes.item(i).name;
48358 if (!currentElement.attributes.item(i).value.length) {
48361 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
48364 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
48373 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
48376 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
48381 // Traverse the tree
48383 var currentElementChild = currentElement.childNodes.item(i);
48384 var allText = true;
48385 var innerHTML = '';
48387 while (currentElementChild) {
48388 // Formatting code (indent the tree so it looks nice on the screen)
48389 var nopad = nopadtext;
48390 if (lastnode == 'SPAN') {
48394 if (currentElementChild.nodeName == '#text') {
48395 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
48396 toadd = nopadtext ? toadd : toadd.trim();
48397 if (!nopad && toadd.length > 80) {
48398 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
48400 innerHTML += toadd;
48403 currentElementChild = currentElement.childNodes.item(i);
48409 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
48411 // Recursively traverse the tree structure of the child node
48412 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
48413 lastnode = currentElementChild.nodeName;
48415 currentElementChild=currentElement.childNodes.item(i);
48421 // The remaining code is mostly for formatting the tree
48422 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
48427 ret+= "</"+tagName+">";
48433 applyBlacklists : function()
48435 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
48436 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
48440 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
48441 if (b.indexOf(tag) > -1) {
48444 this.white.push(tag);
48448 Roo.each(w, function(tag) {
48449 if (b.indexOf(tag) > -1) {
48452 if (this.white.indexOf(tag) > -1) {
48455 this.white.push(tag);
48460 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
48461 if (w.indexOf(tag) > -1) {
48464 this.black.push(tag);
48468 Roo.each(b, function(tag) {
48469 if (w.indexOf(tag) > -1) {
48472 if (this.black.indexOf(tag) > -1) {
48475 this.black.push(tag);
48480 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
48481 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
48485 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
48486 if (b.indexOf(tag) > -1) {
48489 this.cwhite.push(tag);
48493 Roo.each(w, function(tag) {
48494 if (b.indexOf(tag) > -1) {
48497 if (this.cwhite.indexOf(tag) > -1) {
48500 this.cwhite.push(tag);
48505 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
48506 if (w.indexOf(tag) > -1) {
48509 this.cblack.push(tag);
48513 Roo.each(b, function(tag) {
48514 if (w.indexOf(tag) > -1) {
48517 if (this.cblack.indexOf(tag) > -1) {
48520 this.cblack.push(tag);
48525 setStylesheets : function(stylesheets)
48527 if(typeof(stylesheets) == 'string'){
48528 Roo.get(this.iframe.contentDocument.head).createChild({
48530 rel : 'stylesheet',
48539 Roo.each(stylesheets, function(s) {
48544 Roo.get(_this.iframe.contentDocument.head).createChild({
48546 rel : 'stylesheet',
48555 removeStylesheets : function()
48559 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
48564 // hide stuff that is not compatible
48578 * @event specialkey
48582 * @cfg {String} fieldClass @hide
48585 * @cfg {String} focusClass @hide
48588 * @cfg {String} autoCreate @hide
48591 * @cfg {String} inputType @hide
48594 * @cfg {String} invalidClass @hide
48597 * @cfg {String} invalidText @hide
48600 * @cfg {String} msgFx @hide
48603 * @cfg {String} validateOnBlur @hide
48607 Roo.HtmlEditorCore.white = [
48608 'area', 'br', 'img', 'input', 'hr', 'wbr',
48610 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
48611 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
48612 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
48613 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
48614 'table', 'ul', 'xmp',
48616 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
48619 'dir', 'menu', 'ol', 'ul', 'dl',
48625 Roo.HtmlEditorCore.black = [
48626 // 'embed', 'object', // enable - backend responsiblity to clean thiese
48628 'base', 'basefont', 'bgsound', 'blink', 'body',
48629 'frame', 'frameset', 'head', 'html', 'ilayer',
48630 'iframe', 'layer', 'link', 'meta', 'object',
48631 'script', 'style' ,'title', 'xml' // clean later..
48633 Roo.HtmlEditorCore.clean = [
48634 'script', 'style', 'title', 'xml'
48636 Roo.HtmlEditorCore.remove = [
48641 Roo.HtmlEditorCore.ablack = [
48645 Roo.HtmlEditorCore.aclean = [
48646 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
48650 Roo.HtmlEditorCore.pwhite= [
48651 'http', 'https', 'mailto'
48654 // white listed style attributes.
48655 Roo.HtmlEditorCore.cwhite= [
48656 // 'text-align', /// default is to allow most things..
48662 // black listed style attributes.
48663 Roo.HtmlEditorCore.cblack= [
48664 // 'font-size' -- this can be set by the project
48668 Roo.HtmlEditorCore.swapCodes =[
48679 //<script type="text/javascript">
48682 * Ext JS Library 1.1.1
48683 * Copyright(c) 2006-2007, Ext JS, LLC.
48689 Roo.form.HtmlEditor = function(config){
48693 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
48695 if (!this.toolbars) {
48696 this.toolbars = [];
48698 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
48704 * @class Roo.form.HtmlEditor
48705 * @extends Roo.form.Field
48706 * Provides a lightweight HTML Editor component.
48708 * This has been tested on Fireforx / Chrome.. IE may not be so great..
48710 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
48711 * supported by this editor.</b><br/><br/>
48712 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
48713 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
48715 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
48717 * @cfg {Boolean} clearUp
48721 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
48726 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
48731 * @cfg {Number} height (in pixels)
48735 * @cfg {Number} width (in pixels)
48740 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
48743 stylesheets: false,
48747 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
48752 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
48758 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
48763 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
48771 // private properties
48772 validationEvent : false,
48774 initialized : false,
48777 onFocus : Roo.emptyFn,
48779 hideMode:'offsets',
48781 actionMode : 'container', // defaults to hiding it...
48783 defaultAutoCreate : { // modified by initCompnoent..
48785 style:"width:500px;height:300px;",
48786 autocomplete: "new-password"
48790 initComponent : function(){
48793 * @event initialize
48794 * Fires when the editor is fully initialized (including the iframe)
48795 * @param {HtmlEditor} this
48800 * Fires when the editor is first receives the focus. Any insertion must wait
48801 * until after this event.
48802 * @param {HtmlEditor} this
48806 * @event beforesync
48807 * Fires before the textarea is updated with content from the editor iframe. Return false
48808 * to cancel the sync.
48809 * @param {HtmlEditor} this
48810 * @param {String} html
48814 * @event beforepush
48815 * Fires before the iframe editor is updated with content from the textarea. Return false
48816 * to cancel the push.
48817 * @param {HtmlEditor} this
48818 * @param {String} html
48823 * Fires when the textarea is updated with content from the editor iframe.
48824 * @param {HtmlEditor} this
48825 * @param {String} html
48830 * Fires when the iframe editor is updated with content from the textarea.
48831 * @param {HtmlEditor} this
48832 * @param {String} html
48836 * @event editmodechange
48837 * Fires when the editor switches edit modes
48838 * @param {HtmlEditor} this
48839 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
48841 editmodechange: true,
48843 * @event editorevent
48844 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
48845 * @param {HtmlEditor} this
48849 * @event firstfocus
48850 * Fires when on first focus - needed by toolbars..
48851 * @param {HtmlEditor} this
48856 * Auto save the htmlEditor value as a file into Events
48857 * @param {HtmlEditor} this
48861 * @event savedpreview
48862 * preview the saved version of htmlEditor
48863 * @param {HtmlEditor} this
48865 savedpreview: true,
48868 * @event stylesheetsclick
48869 * Fires when press the Sytlesheets button
48870 * @param {Roo.HtmlEditorCore} this
48872 stylesheetsclick: true
48874 this.defaultAutoCreate = {
48876 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
48877 autocomplete: "new-password"
48882 * Protected method that will not generally be called directly. It
48883 * is called when the editor creates its toolbar. Override this method if you need to
48884 * add custom toolbar buttons.
48885 * @param {HtmlEditor} editor
48887 createToolbar : function(editor){
48888 Roo.log("create toolbars");
48889 if (!editor.toolbars || !editor.toolbars.length) {
48890 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
48893 for (var i =0 ; i < editor.toolbars.length;i++) {
48894 editor.toolbars[i] = Roo.factory(
48895 typeof(editor.toolbars[i]) == 'string' ?
48896 { xtype: editor.toolbars[i]} : editor.toolbars[i],
48897 Roo.form.HtmlEditor);
48898 editor.toolbars[i].init(editor);
48906 onRender : function(ct, position)
48909 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
48911 this.wrap = this.el.wrap({
48912 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
48915 this.editorcore.onRender(ct, position);
48917 if (this.resizable) {
48918 this.resizeEl = new Roo.Resizable(this.wrap, {
48922 minHeight : this.height,
48923 height: this.height,
48924 handles : this.resizable,
48927 resize : function(r, w, h) {
48928 _t.onResize(w,h); // -something
48934 this.createToolbar(this);
48938 this.setSize(this.wrap.getSize());
48940 if (this.resizeEl) {
48941 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
48942 // should trigger onReize..
48945 this.keyNav = new Roo.KeyNav(this.el, {
48947 "tab" : function(e){
48948 e.preventDefault();
48950 var value = this.getValue();
48952 var start = this.el.dom.selectionStart;
48953 var end = this.el.dom.selectionEnd;
48957 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
48958 this.el.dom.setSelectionRange(end + 1, end + 1);
48962 var f = value.substring(0, start).split("\t");
48964 if(f.pop().length != 0){
48968 this.setValue(f.join("\t") + value.substring(end));
48969 this.el.dom.setSelectionRange(start - 1, start - 1);
48973 "home" : function(e){
48974 e.preventDefault();
48976 var curr = this.el.dom.selectionStart;
48977 var lines = this.getValue().split("\n");
48984 this.el.dom.setSelectionRange(0, 0);
48990 for (var i = 0; i < lines.length;i++) {
48991 pos += lines[i].length;
49001 pos -= lines[i].length;
49007 this.el.dom.setSelectionRange(pos, pos);
49011 this.el.dom.selectionStart = pos;
49012 this.el.dom.selectionEnd = curr;
49015 "end" : function(e){
49016 e.preventDefault();
49018 var curr = this.el.dom.selectionStart;
49019 var lines = this.getValue().split("\n");
49026 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
49032 for (var i = 0; i < lines.length;i++) {
49034 pos += lines[i].length;
49048 this.el.dom.setSelectionRange(pos, pos);
49052 this.el.dom.selectionStart = curr;
49053 this.el.dom.selectionEnd = pos;
49058 doRelay : function(foo, bar, hname){
49059 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
49065 // if(this.autosave && this.w){
49066 // this.autoSaveFn = setInterval(this.autosave, 1000);
49071 onResize : function(w, h)
49073 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
49078 if(typeof w == 'number'){
49079 var aw = w - this.wrap.getFrameWidth('lr');
49080 this.el.setWidth(this.adjustWidth('textarea', aw));
49083 if(typeof h == 'number'){
49085 for (var i =0; i < this.toolbars.length;i++) {
49086 // fixme - ask toolbars for heights?
49087 tbh += this.toolbars[i].tb.el.getHeight();
49088 if (this.toolbars[i].footer) {
49089 tbh += this.toolbars[i].footer.el.getHeight();
49096 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
49097 ah -= 5; // knock a few pixes off for look..
49099 this.el.setHeight(this.adjustWidth('textarea', ah));
49103 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
49104 this.editorcore.onResize(ew,eh);
49109 * Toggles the editor between standard and source edit mode.
49110 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
49112 toggleSourceEdit : function(sourceEditMode)
49114 this.editorcore.toggleSourceEdit(sourceEditMode);
49116 if(this.editorcore.sourceEditMode){
49117 Roo.log('editor - showing textarea');
49120 // Roo.log(this.syncValue());
49121 this.editorcore.syncValue();
49122 this.el.removeClass('x-hidden');
49123 this.el.dom.removeAttribute('tabIndex');
49126 for (var i = 0; i < this.toolbars.length; i++) {
49127 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
49128 this.toolbars[i].tb.hide();
49129 this.toolbars[i].footer.hide();
49134 Roo.log('editor - hiding textarea');
49136 // Roo.log(this.pushValue());
49137 this.editorcore.pushValue();
49139 this.el.addClass('x-hidden');
49140 this.el.dom.setAttribute('tabIndex', -1);
49142 for (var i = 0; i < this.toolbars.length; i++) {
49143 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
49144 this.toolbars[i].tb.show();
49145 this.toolbars[i].footer.show();
49149 //this.deferFocus();
49152 this.setSize(this.wrap.getSize());
49153 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
49155 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
49158 // private (for BoxComponent)
49159 adjustSize : Roo.BoxComponent.prototype.adjustSize,
49161 // private (for BoxComponent)
49162 getResizeEl : function(){
49166 // private (for BoxComponent)
49167 getPositionEl : function(){
49172 initEvents : function(){
49173 this.originalValue = this.getValue();
49177 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
49180 markInvalid : Roo.emptyFn,
49182 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
49185 clearInvalid : Roo.emptyFn,
49187 setValue : function(v){
49188 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
49189 this.editorcore.pushValue();
49194 deferFocus : function(){
49195 this.focus.defer(10, this);
49199 focus : function(){
49200 this.editorcore.focus();
49206 onDestroy : function(){
49212 for (var i =0; i < this.toolbars.length;i++) {
49213 // fixme - ask toolbars for heights?
49214 this.toolbars[i].onDestroy();
49217 this.wrap.dom.innerHTML = '';
49218 this.wrap.remove();
49223 onFirstFocus : function(){
49224 //Roo.log("onFirstFocus");
49225 this.editorcore.onFirstFocus();
49226 for (var i =0; i < this.toolbars.length;i++) {
49227 this.toolbars[i].onFirstFocus();
49233 syncValue : function()
49235 this.editorcore.syncValue();
49238 pushValue : function()
49240 this.editorcore.pushValue();
49243 setStylesheets : function(stylesheets)
49245 this.editorcore.setStylesheets(stylesheets);
49248 removeStylesheets : function()
49250 this.editorcore.removeStylesheets();
49254 // hide stuff that is not compatible
49268 * @event specialkey
49272 * @cfg {String} fieldClass @hide
49275 * @cfg {String} focusClass @hide
49278 * @cfg {String} autoCreate @hide
49281 * @cfg {String} inputType @hide
49284 * @cfg {String} invalidClass @hide
49287 * @cfg {String} invalidText @hide
49290 * @cfg {String} msgFx @hide
49293 * @cfg {String} validateOnBlur @hide
49297 // <script type="text/javascript">
49300 * Ext JS Library 1.1.1
49301 * Copyright(c) 2006-2007, Ext JS, LLC.
49307 * @class Roo.form.HtmlEditorToolbar1
49312 new Roo.form.HtmlEditor({
49315 new Roo.form.HtmlEditorToolbar1({
49316 disable : { fonts: 1 , format: 1, ..., ... , ...],
49322 * @cfg {Object} disable List of elements to disable..
49323 * @cfg {Array} btns List of additional buttons.
49327 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
49330 Roo.form.HtmlEditor.ToolbarStandard = function(config)
49333 Roo.apply(this, config);
49335 // default disabled, based on 'good practice'..
49336 this.disable = this.disable || {};
49337 Roo.applyIf(this.disable, {
49340 specialElements : true
49344 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
49345 // dont call parent... till later.
49348 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
49355 editorcore : false,
49357 * @cfg {Object} disable List of toolbar elements to disable
49364 * @cfg {String} createLinkText The default text for the create link prompt
49366 createLinkText : 'Please enter the URL for the link:',
49368 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
49370 defaultLinkValue : 'http:/'+'/',
49374 * @cfg {Array} fontFamilies An array of available font families
49392 // "á" , ?? a acute?
49397 "°" // , // degrees
49399 // "é" , // e ecute
49400 // "ú" , // u ecute?
49403 specialElements : [
49405 text: "Insert Table",
49408 ihtml : '<table><tr><td>Cell</td></tr></table>'
49412 text: "Insert Image",
49415 ihtml : '<img src="about:blank"/>'
49424 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
49425 "input:submit", "input:button", "select", "textarea", "label" ],
49428 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
49430 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
49438 * @cfg {String} defaultFont default font to use.
49440 defaultFont: 'tahoma',
49442 fontSelect : false,
49445 formatCombo : false,
49447 init : function(editor)
49449 this.editor = editor;
49450 this.editorcore = editor.editorcore ? editor.editorcore : editor;
49451 var editorcore = this.editorcore;
49455 var fid = editorcore.frameId;
49457 function btn(id, toggle, handler){
49458 var xid = fid + '-'+ id ;
49462 cls : 'x-btn-icon x-edit-'+id,
49463 enableToggle:toggle !== false,
49464 scope: _t, // was editor...
49465 handler:handler||_t.relayBtnCmd,
49466 clickEvent:'mousedown',
49467 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49474 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49476 // stop form submits
49477 tb.el.on('click', function(e){
49478 e.preventDefault(); // what does this do?
49481 if(!this.disable.font) { // && !Roo.isSafari){
49482 /* why no safari for fonts
49483 editor.fontSelect = tb.el.createChild({
49486 cls:'x-font-select',
49487 html: this.createFontOptions()
49490 editor.fontSelect.on('change', function(){
49491 var font = editor.fontSelect.dom.value;
49492 editor.relayCmd('fontname', font);
49493 editor.deferFocus();
49497 editor.fontSelect.dom,
49503 if(!this.disable.formats){
49504 this.formatCombo = new Roo.form.ComboBox({
49505 store: new Roo.data.SimpleStore({
49508 data : this.formats // from states.js
49512 //autoCreate : {tag: "div", size: "20"},
49513 displayField:'tag',
49517 triggerAction: 'all',
49518 emptyText:'Add tag',
49519 selectOnFocus:true,
49522 'select': function(c, r, i) {
49523 editorcore.insertTag(r.get('tag'));
49529 tb.addField(this.formatCombo);
49533 if(!this.disable.format){
49538 btn('strikethrough')
49541 if(!this.disable.fontSize){
49546 btn('increasefontsize', false, editorcore.adjustFont),
49547 btn('decreasefontsize', false, editorcore.adjustFont)
49552 if(!this.disable.colors){
49555 id:editorcore.frameId +'-forecolor',
49556 cls:'x-btn-icon x-edit-forecolor',
49557 clickEvent:'mousedown',
49558 tooltip: this.buttonTips['forecolor'] || undefined,
49560 menu : new Roo.menu.ColorMenu({
49561 allowReselect: true,
49562 focus: Roo.emptyFn,
49565 selectHandler: function(cp, color){
49566 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
49567 editor.deferFocus();
49570 clickEvent:'mousedown'
49573 id:editorcore.frameId +'backcolor',
49574 cls:'x-btn-icon x-edit-backcolor',
49575 clickEvent:'mousedown',
49576 tooltip: this.buttonTips['backcolor'] || undefined,
49578 menu : new Roo.menu.ColorMenu({
49579 focus: Roo.emptyFn,
49582 allowReselect: true,
49583 selectHandler: function(cp, color){
49585 editorcore.execCmd('useCSS', false);
49586 editorcore.execCmd('hilitecolor', color);
49587 editorcore.execCmd('useCSS', true);
49588 editor.deferFocus();
49590 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
49591 Roo.isSafari || Roo.isIE ? '#'+color : color);
49592 editor.deferFocus();
49596 clickEvent:'mousedown'
49601 // now add all the items...
49604 if(!this.disable.alignments){
49607 btn('justifyleft'),
49608 btn('justifycenter'),
49609 btn('justifyright')
49613 //if(!Roo.isSafari){
49614 if(!this.disable.links){
49617 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
49621 if(!this.disable.lists){
49624 btn('insertorderedlist'),
49625 btn('insertunorderedlist')
49628 if(!this.disable.sourceEdit){
49631 btn('sourceedit', true, function(btn){
49632 this.toggleSourceEdit(btn.pressed);
49639 // special menu.. - needs to be tidied up..
49640 if (!this.disable.special) {
49643 cls: 'x-edit-none',
49649 for (var i =0; i < this.specialChars.length; i++) {
49650 smenu.menu.items.push({
49652 html: this.specialChars[i],
49653 handler: function(a,b) {
49654 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
49655 //editor.insertAtCursor(a.html);
49669 if (!this.disable.cleanStyles) {
49671 cls: 'x-btn-icon x-btn-clear',
49677 for (var i =0; i < this.cleanStyles.length; i++) {
49678 cmenu.menu.items.push({
49679 actiontype : this.cleanStyles[i],
49680 html: 'Remove ' + this.cleanStyles[i],
49681 handler: function(a,b) {
49684 var c = Roo.get(editorcore.doc.body);
49685 c.select('[style]').each(function(s) {
49686 s.dom.style.removeProperty(a.actiontype);
49688 editorcore.syncValue();
49693 cmenu.menu.items.push({
49694 actiontype : 'tablewidths',
49695 html: 'Remove Table Widths',
49696 handler: function(a,b) {
49697 editorcore.cleanTableWidths();
49698 editorcore.syncValue();
49702 cmenu.menu.items.push({
49703 actiontype : 'word',
49704 html: 'Remove MS Word Formating',
49705 handler: function(a,b) {
49706 editorcore.cleanWord();
49707 editorcore.syncValue();
49712 cmenu.menu.items.push({
49713 actiontype : 'all',
49714 html: 'Remove All Styles',
49715 handler: function(a,b) {
49717 var c = Roo.get(editorcore.doc.body);
49718 c.select('[style]').each(function(s) {
49719 s.dom.removeAttribute('style');
49721 editorcore.syncValue();
49726 cmenu.menu.items.push({
49727 actiontype : 'all',
49728 html: 'Remove All CSS Classes',
49729 handler: function(a,b) {
49731 var c = Roo.get(editorcore.doc.body);
49732 c.select('[class]').each(function(s) {
49733 s.dom.className = '';
49735 editorcore.syncValue();
49740 cmenu.menu.items.push({
49741 actiontype : 'tidy',
49742 html: 'Tidy HTML Source',
49743 handler: function(a,b) {
49744 editorcore.doc.body.innerHTML = editorcore.domToHTML();
49745 editorcore.syncValue();
49754 if (!this.disable.specialElements) {
49757 cls: 'x-edit-none',
49762 for (var i =0; i < this.specialElements.length; i++) {
49763 semenu.menu.items.push(
49765 handler: function(a,b) {
49766 editor.insertAtCursor(this.ihtml);
49768 }, this.specialElements[i])
49780 for(var i =0; i< this.btns.length;i++) {
49781 var b = Roo.factory(this.btns[i],Roo.form);
49782 b.cls = 'x-edit-none';
49784 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
49785 b.cls += ' x-init-enable';
49788 b.scope = editorcore;
49796 // disable everything...
49798 this.tb.items.each(function(item){
49801 item.id != editorcore.frameId+ '-sourceedit' &&
49802 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
49808 this.rendered = true;
49810 // the all the btns;
49811 editor.on('editorevent', this.updateToolbar, this);
49812 // other toolbars need to implement this..
49813 //editor.on('editmodechange', this.updateToolbar, this);
49817 relayBtnCmd : function(btn) {
49818 this.editorcore.relayCmd(btn.cmd);
49820 // private used internally
49821 createLink : function(){
49822 Roo.log("create link?");
49823 var url = prompt(this.createLinkText, this.defaultLinkValue);
49824 if(url && url != 'http:/'+'/'){
49825 this.editorcore.relayCmd('createlink', url);
49831 * Protected method that will not generally be called directly. It triggers
49832 * a toolbar update by reading the markup state of the current selection in the editor.
49834 updateToolbar: function(){
49836 if(!this.editorcore.activated){
49837 this.editor.onFirstFocus();
49841 var btns = this.tb.items.map,
49842 doc = this.editorcore.doc,
49843 frameId = this.editorcore.frameId;
49845 if(!this.disable.font && !Roo.isSafari){
49847 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
49848 if(name != this.fontSelect.dom.value){
49849 this.fontSelect.dom.value = name;
49853 if(!this.disable.format){
49854 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
49855 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
49856 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
49857 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
49859 if(!this.disable.alignments){
49860 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
49861 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
49862 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
49864 if(!Roo.isSafari && !this.disable.lists){
49865 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
49866 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
49869 var ans = this.editorcore.getAllAncestors();
49870 if (this.formatCombo) {
49873 var store = this.formatCombo.store;
49874 this.formatCombo.setValue("");
49875 for (var i =0; i < ans.length;i++) {
49876 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
49878 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
49886 // hides menus... - so this cant be on a menu...
49887 Roo.menu.MenuMgr.hideAll();
49889 //this.editorsyncValue();
49893 createFontOptions : function(){
49894 var buf = [], fs = this.fontFamilies, ff, lc;
49898 for(var i = 0, len = fs.length; i< len; i++){
49900 lc = ff.toLowerCase();
49902 '<option value="',lc,'" style="font-family:',ff,';"',
49903 (this.defaultFont == lc ? ' selected="true">' : '>'),
49908 return buf.join('');
49911 toggleSourceEdit : function(sourceEditMode){
49913 Roo.log("toolbar toogle");
49914 if(sourceEditMode === undefined){
49915 sourceEditMode = !this.sourceEditMode;
49917 this.sourceEditMode = sourceEditMode === true;
49918 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
49919 // just toggle the button?
49920 if(btn.pressed !== this.sourceEditMode){
49921 btn.toggle(this.sourceEditMode);
49925 if(sourceEditMode){
49926 Roo.log("disabling buttons");
49927 this.tb.items.each(function(item){
49928 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
49934 Roo.log("enabling buttons");
49935 if(this.editorcore.initialized){
49936 this.tb.items.each(function(item){
49942 Roo.log("calling toggole on editor");
49943 // tell the editor that it's been pressed..
49944 this.editor.toggleSourceEdit(sourceEditMode);
49948 * Object collection of toolbar tooltips for the buttons in the editor. The key
49949 * is the command id associated with that button and the value is a valid QuickTips object.
49954 title: 'Bold (Ctrl+B)',
49955 text: 'Make the selected text bold.',
49956 cls: 'x-html-editor-tip'
49959 title: 'Italic (Ctrl+I)',
49960 text: 'Make the selected text italic.',
49961 cls: 'x-html-editor-tip'
49969 title: 'Bold (Ctrl+B)',
49970 text: 'Make the selected text bold.',
49971 cls: 'x-html-editor-tip'
49974 title: 'Italic (Ctrl+I)',
49975 text: 'Make the selected text italic.',
49976 cls: 'x-html-editor-tip'
49979 title: 'Underline (Ctrl+U)',
49980 text: 'Underline the selected text.',
49981 cls: 'x-html-editor-tip'
49984 title: 'Strikethrough',
49985 text: 'Strikethrough the selected text.',
49986 cls: 'x-html-editor-tip'
49988 increasefontsize : {
49989 title: 'Grow Text',
49990 text: 'Increase the font size.',
49991 cls: 'x-html-editor-tip'
49993 decreasefontsize : {
49994 title: 'Shrink Text',
49995 text: 'Decrease the font size.',
49996 cls: 'x-html-editor-tip'
49999 title: 'Text Highlight Color',
50000 text: 'Change the background color of the selected text.',
50001 cls: 'x-html-editor-tip'
50004 title: 'Font Color',
50005 text: 'Change the color of the selected text.',
50006 cls: 'x-html-editor-tip'
50009 title: 'Align Text Left',
50010 text: 'Align text to the left.',
50011 cls: 'x-html-editor-tip'
50014 title: 'Center Text',
50015 text: 'Center text in the editor.',
50016 cls: 'x-html-editor-tip'
50019 title: 'Align Text Right',
50020 text: 'Align text to the right.',
50021 cls: 'x-html-editor-tip'
50023 insertunorderedlist : {
50024 title: 'Bullet List',
50025 text: 'Start a bulleted list.',
50026 cls: 'x-html-editor-tip'
50028 insertorderedlist : {
50029 title: 'Numbered List',
50030 text: 'Start a numbered list.',
50031 cls: 'x-html-editor-tip'
50034 title: 'Hyperlink',
50035 text: 'Make the selected text a hyperlink.',
50036 cls: 'x-html-editor-tip'
50039 title: 'Source Edit',
50040 text: 'Switch to source editing mode.',
50041 cls: 'x-html-editor-tip'
50045 onDestroy : function(){
50048 this.tb.items.each(function(item){
50050 item.menu.removeAll();
50052 item.menu.el.destroy();
50060 onFirstFocus: function() {
50061 this.tb.items.each(function(item){
50070 // <script type="text/javascript">
50073 * Ext JS Library 1.1.1
50074 * Copyright(c) 2006-2007, Ext JS, LLC.
50081 * @class Roo.form.HtmlEditor.ToolbarContext
50086 new Roo.form.HtmlEditor({
50089 { xtype: 'ToolbarStandard', styles : {} }
50090 { xtype: 'ToolbarContext', disable : {} }
50096 * @config : {Object} disable List of elements to disable.. (not done yet.)
50097 * @config : {Object} styles Map of styles available.
50101 Roo.form.HtmlEditor.ToolbarContext = function(config)
50104 Roo.apply(this, config);
50105 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
50106 // dont call parent... till later.
50107 this.styles = this.styles || {};
50112 Roo.form.HtmlEditor.ToolbarContext.types = {
50124 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
50190 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
50195 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
50205 style : 'fontFamily',
50206 displayField: 'display',
50207 optname : 'font-family',
50256 // should we really allow this??
50257 // should this just be
50268 style : 'fontFamily',
50269 displayField: 'display',
50270 optname : 'font-family',
50277 style : 'fontFamily',
50278 displayField: 'display',
50279 optname : 'font-family',
50286 style : 'fontFamily',
50287 displayField: 'display',
50288 optname : 'font-family',
50299 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
50300 Roo.form.HtmlEditor.ToolbarContext.stores = false;
50302 Roo.form.HtmlEditor.ToolbarContext.options = {
50304 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
50305 [ 'Courier New', 'Courier New'],
50306 [ 'Tahoma', 'Tahoma'],
50307 [ 'Times New Roman,serif', 'Times'],
50308 [ 'Verdana','Verdana' ]
50312 // fixme - these need to be configurable..
50315 //Roo.form.HtmlEditor.ToolbarContext.types
50318 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
50325 editorcore : false,
50327 * @cfg {Object} disable List of toolbar elements to disable
50332 * @cfg {Object} styles List of styles
50333 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
50335 * These must be defined in the page, so they get rendered correctly..
50346 init : function(editor)
50348 this.editor = editor;
50349 this.editorcore = editor.editorcore ? editor.editorcore : editor;
50350 var editorcore = this.editorcore;
50352 var fid = editorcore.frameId;
50354 function btn(id, toggle, handler){
50355 var xid = fid + '-'+ id ;
50359 cls : 'x-btn-icon x-edit-'+id,
50360 enableToggle:toggle !== false,
50361 scope: editorcore, // was editor...
50362 handler:handler||editorcore.relayBtnCmd,
50363 clickEvent:'mousedown',
50364 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50368 // create a new element.
50369 var wdiv = editor.wrap.createChild({
50371 }, editor.wrap.dom.firstChild.nextSibling, true);
50373 // can we do this more than once??
50375 // stop form submits
50378 // disable everything...
50379 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
50380 this.toolbars = {};
50382 for (var i in ty) {
50384 this.toolbars[i] = this.buildToolbar(ty[i],i);
50386 this.tb = this.toolbars.BODY;
50388 this.buildFooter();
50389 this.footer.show();
50390 editor.on('hide', function( ) { this.footer.hide() }, this);
50391 editor.on('show', function( ) { this.footer.show() }, this);
50394 this.rendered = true;
50396 // the all the btns;
50397 editor.on('editorevent', this.updateToolbar, this);
50398 // other toolbars need to implement this..
50399 //editor.on('editmodechange', this.updateToolbar, this);
50405 * Protected method that will not generally be called directly. It triggers
50406 * a toolbar update by reading the markup state of the current selection in the editor.
50408 * Note you can force an update by calling on('editorevent', scope, false)
50410 updateToolbar: function(editor,ev,sel){
50413 // capture mouse up - this is handy for selecting images..
50414 // perhaps should go somewhere else...
50415 if(!this.editorcore.activated){
50416 this.editor.onFirstFocus();
50422 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
50423 // selectNode - might want to handle IE?
50425 (ev.type == 'mouseup' || ev.type == 'click' ) &&
50426 ev.target && ev.target.tagName == 'IMG') {
50427 // they have click on an image...
50428 // let's see if we can change the selection...
50431 var nodeRange = sel.ownerDocument.createRange();
50433 nodeRange.selectNode(sel);
50435 nodeRange.selectNodeContents(sel);
50437 //nodeRange.collapse(true);
50438 var s = this.editorcore.win.getSelection();
50439 s.removeAllRanges();
50440 s.addRange(nodeRange);
50444 var updateFooter = sel ? false : true;
50447 var ans = this.editorcore.getAllAncestors();
50450 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
50453 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
50454 sel = sel ? sel : this.editorcore.doc.body;
50455 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
50458 // pick a menu that exists..
50459 var tn = sel.tagName.toUpperCase();
50460 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
50462 tn = sel.tagName.toUpperCase();
50464 var lastSel = this.tb.selectedNode;
50466 this.tb.selectedNode = sel;
50468 // if current menu does not match..
50470 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
50473 ///console.log("show: " + tn);
50474 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
50477 this.tb.items.first().el.innerHTML = tn + ': ';
50480 // update attributes
50481 if (this.tb.fields) {
50482 this.tb.fields.each(function(e) {
50484 e.setValue(sel.style[e.stylename]);
50487 e.setValue(sel.getAttribute(e.attrname));
50491 var hasStyles = false;
50492 for(var i in this.styles) {
50499 var st = this.tb.fields.item(0);
50501 st.store.removeAll();
50504 var cn = sel.className.split(/\s+/);
50507 if (this.styles['*']) {
50509 Roo.each(this.styles['*'], function(v) {
50510 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
50513 if (this.styles[tn]) {
50514 Roo.each(this.styles[tn], function(v) {
50515 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
50519 st.store.loadData(avs);
50523 // flag our selected Node.
50524 this.tb.selectedNode = sel;
50527 Roo.menu.MenuMgr.hideAll();
50531 if (!updateFooter) {
50532 //this.footDisp.dom.innerHTML = '';
50535 // update the footer
50539 this.footerEls = ans.reverse();
50540 Roo.each(this.footerEls, function(a,i) {
50541 if (!a) { return; }
50542 html += html.length ? ' > ' : '';
50544 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
50549 var sz = this.footDisp.up('td').getSize();
50550 this.footDisp.dom.style.width = (sz.width -10) + 'px';
50551 this.footDisp.dom.style.marginLeft = '5px';
50553 this.footDisp.dom.style.overflow = 'hidden';
50555 this.footDisp.dom.innerHTML = html;
50557 //this.editorsyncValue();
50564 onDestroy : function(){
50567 this.tb.items.each(function(item){
50569 item.menu.removeAll();
50571 item.menu.el.destroy();
50579 onFirstFocus: function() {
50580 // need to do this for all the toolbars..
50581 this.tb.items.each(function(item){
50585 buildToolbar: function(tlist, nm)
50587 var editor = this.editor;
50588 var editorcore = this.editorcore;
50589 // create a new element.
50590 var wdiv = editor.wrap.createChild({
50592 }, editor.wrap.dom.firstChild.nextSibling, true);
50595 var tb = new Roo.Toolbar(wdiv);
50598 tb.add(nm+ ": ");
50601 for(var i in this.styles) {
50606 if (styles && styles.length) {
50608 // this needs a multi-select checkbox...
50609 tb.addField( new Roo.form.ComboBox({
50610 store: new Roo.data.SimpleStore({
50612 fields: ['val', 'selected'],
50615 name : '-roo-edit-className',
50616 attrname : 'className',
50617 displayField: 'val',
50621 triggerAction: 'all',
50622 emptyText:'Select Style',
50623 selectOnFocus:true,
50626 'select': function(c, r, i) {
50627 // initial support only for on class per el..
50628 tb.selectedNode.className = r ? r.get('val') : '';
50629 editorcore.syncValue();
50636 var tbc = Roo.form.HtmlEditor.ToolbarContext;
50637 var tbops = tbc.options;
50639 for (var i in tlist) {
50641 var item = tlist[i];
50642 tb.add(item.title + ": ");
50645 //optname == used so you can configure the options available..
50646 var opts = item.opts ? item.opts : false;
50647 if (item.optname) {
50648 opts = tbops[item.optname];
50653 // opts == pulldown..
50654 tb.addField( new Roo.form.ComboBox({
50655 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
50657 fields: ['val', 'display'],
50660 name : '-roo-edit-' + i,
50662 stylename : item.style ? item.style : false,
50663 displayField: item.displayField ? item.displayField : 'val',
50664 valueField : 'val',
50666 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
50668 triggerAction: 'all',
50669 emptyText:'Select',
50670 selectOnFocus:true,
50671 width: item.width ? item.width : 130,
50673 'select': function(c, r, i) {
50675 tb.selectedNode.style[c.stylename] = r.get('val');
50678 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
50687 tb.addField( new Roo.form.TextField({
50690 //allowBlank:false,
50695 tb.addField( new Roo.form.TextField({
50696 name: '-roo-edit-' + i,
50703 'change' : function(f, nv, ov) {
50704 tb.selectedNode.setAttribute(f.attrname, nv);
50705 editorcore.syncValue();
50718 text: 'Stylesheets',
50721 click : function ()
50723 _this.editor.fireEvent('stylesheetsclick', _this.editor);
50731 text: 'Remove Tag',
50734 click : function ()
50737 // undo does not work.
50739 var sn = tb.selectedNode;
50741 var pn = sn.parentNode;
50743 var stn = sn.childNodes[0];
50744 var en = sn.childNodes[sn.childNodes.length - 1 ];
50745 while (sn.childNodes.length) {
50746 var node = sn.childNodes[0];
50747 sn.removeChild(node);
50749 pn.insertBefore(node, sn);
50752 pn.removeChild(sn);
50753 var range = editorcore.createRange();
50755 range.setStart(stn,0);
50756 range.setEnd(en,0); //????
50757 //range.selectNode(sel);
50760 var selection = editorcore.getSelection();
50761 selection.removeAllRanges();
50762 selection.addRange(range);
50766 //_this.updateToolbar(null, null, pn);
50767 _this.updateToolbar(null, null, null);
50768 _this.footDisp.dom.innerHTML = '';
50778 tb.el.on('click', function(e){
50779 e.preventDefault(); // what does this do?
50781 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
50784 // dont need to disable them... as they will get hidden
50789 buildFooter : function()
50792 var fel = this.editor.wrap.createChild();
50793 this.footer = new Roo.Toolbar(fel);
50794 // toolbar has scrolly on left / right?
50795 var footDisp= new Roo.Toolbar.Fill();
50801 handler : function() {
50802 _t.footDisp.scrollTo('left',0,true)
50806 this.footer.add( footDisp );
50811 handler : function() {
50813 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
50817 var fel = Roo.get(footDisp.el);
50818 fel.addClass('x-editor-context');
50819 this.footDispWrap = fel;
50820 this.footDispWrap.overflow = 'hidden';
50822 this.footDisp = fel.createChild();
50823 this.footDispWrap.on('click', this.onContextClick, this)
50827 onContextClick : function (ev,dom)
50829 ev.preventDefault();
50830 var cn = dom.className;
50832 if (!cn.match(/x-ed-loc-/)) {
50835 var n = cn.split('-').pop();
50836 var ans = this.footerEls;
50840 var range = this.editorcore.createRange();
50842 range.selectNodeContents(sel);
50843 //range.selectNode(sel);
50846 var selection = this.editorcore.getSelection();
50847 selection.removeAllRanges();
50848 selection.addRange(range);
50852 this.updateToolbar(null, null, sel);
50869 * Ext JS Library 1.1.1
50870 * Copyright(c) 2006-2007, Ext JS, LLC.
50872 * Originally Released Under LGPL - original licence link has changed is not relivant.
50875 * <script type="text/javascript">
50879 * @class Roo.form.BasicForm
50880 * @extends Roo.util.Observable
50881 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
50883 * @param {String/HTMLElement/Roo.Element} el The form element or its id
50884 * @param {Object} config Configuration options
50886 Roo.form.BasicForm = function(el, config){
50887 this.allItems = [];
50888 this.childForms = [];
50889 Roo.apply(this, config);
50891 * The Roo.form.Field items in this form.
50892 * @type MixedCollection
50896 this.items = new Roo.util.MixedCollection(false, function(o){
50897 return o.id || (o.id = Roo.id());
50901 * @event beforeaction
50902 * Fires before any action is performed. Return false to cancel the action.
50903 * @param {Form} this
50904 * @param {Action} action The action to be performed
50906 beforeaction: true,
50908 * @event actionfailed
50909 * Fires when an action fails.
50910 * @param {Form} this
50911 * @param {Action} action The action that failed
50913 actionfailed : true,
50915 * @event actioncomplete
50916 * Fires when an action is completed.
50917 * @param {Form} this
50918 * @param {Action} action The action that completed
50920 actioncomplete : true
50925 Roo.form.BasicForm.superclass.constructor.call(this);
50928 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
50930 * @cfg {String} method
50931 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
50934 * @cfg {DataReader} reader
50935 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
50936 * This is optional as there is built-in support for processing JSON.
50939 * @cfg {DataReader} errorReader
50940 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
50941 * This is completely optional as there is built-in support for processing JSON.
50944 * @cfg {String} url
50945 * The URL to use for form actions if one isn't supplied in the action options.
50948 * @cfg {Boolean} fileUpload
50949 * Set to true if this form is a file upload.
50953 * @cfg {Object} baseParams
50954 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
50959 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
50964 activeAction : null,
50967 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
50968 * or setValues() data instead of when the form was first created.
50970 trackResetOnLoad : false,
50974 * childForms - used for multi-tab forms
50977 childForms : false,
50980 * allItems - full list of fields.
50986 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
50987 * element by passing it or its id or mask the form itself by passing in true.
50990 waitMsgTarget : false,
50993 initEl : function(el){
50994 this.el = Roo.get(el);
50995 this.id = this.el.id || Roo.id();
50996 this.el.on('submit', this.onSubmit, this);
50997 this.el.addClass('x-form');
51001 onSubmit : function(e){
51006 * Returns true if client-side validation on the form is successful.
51009 isValid : function(){
51011 this.items.each(function(f){
51020 * DEPRICATED Returns true if any fields in this form have changed since their original load.
51023 isDirty : function(){
51025 this.items.each(function(f){
51035 * Returns true if any fields in this form have changed since their original load. (New version)
51039 hasChanged : function()
51042 this.items.each(function(f){
51043 if(f.hasChanged()){
51052 * Resets all hasChanged to 'false' -
51053 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
51054 * So hasChanged storage is only to be used for this purpose
51057 resetHasChanged : function()
51059 this.items.each(function(f){
51060 f.resetHasChanged();
51067 * Performs a predefined action (submit or load) or custom actions you define on this form.
51068 * @param {String} actionName The name of the action type
51069 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
51070 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
51071 * accept other config options):
51073 Property Type Description
51074 ---------------- --------------- ----------------------------------------------------------------------------------
51075 url String The url for the action (defaults to the form's url)
51076 method String The form method to use (defaults to the form's method, or POST if not defined)
51077 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
51078 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
51079 validate the form on the client (defaults to false)
51081 * @return {BasicForm} this
51083 doAction : function(action, options){
51084 if(typeof action == 'string'){
51085 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
51087 if(this.fireEvent('beforeaction', this, action) !== false){
51088 this.beforeAction(action);
51089 action.run.defer(100, action);
51095 * Shortcut to do a submit action.
51096 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
51097 * @return {BasicForm} this
51099 submit : function(options){
51100 this.doAction('submit', options);
51105 * Shortcut to do a load action.
51106 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
51107 * @return {BasicForm} this
51109 load : function(options){
51110 this.doAction('load', options);
51115 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
51116 * @param {Record} record The record to edit
51117 * @return {BasicForm} this
51119 updateRecord : function(record){
51120 record.beginEdit();
51121 var fs = record.fields;
51122 fs.each(function(f){
51123 var field = this.findField(f.name);
51125 record.set(f.name, field.getValue());
51133 * Loads an Roo.data.Record into this form.
51134 * @param {Record} record The record to load
51135 * @return {BasicForm} this
51137 loadRecord : function(record){
51138 this.setValues(record.data);
51143 beforeAction : function(action){
51144 var o = action.options;
51147 if(this.waitMsgTarget === true){
51148 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
51149 }else if(this.waitMsgTarget){
51150 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
51151 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
51153 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
51159 afterAction : function(action, success){
51160 this.activeAction = null;
51161 var o = action.options;
51163 if(this.waitMsgTarget === true){
51165 }else if(this.waitMsgTarget){
51166 this.waitMsgTarget.unmask();
51168 Roo.MessageBox.updateProgress(1);
51169 Roo.MessageBox.hide();
51176 Roo.callback(o.success, o.scope, [this, action]);
51177 this.fireEvent('actioncomplete', this, action);
51181 // failure condition..
51182 // we have a scenario where updates need confirming.
51183 // eg. if a locking scenario exists..
51184 // we look for { errors : { needs_confirm : true }} in the response.
51186 (typeof(action.result) != 'undefined') &&
51187 (typeof(action.result.errors) != 'undefined') &&
51188 (typeof(action.result.errors.needs_confirm) != 'undefined')
51191 Roo.MessageBox.confirm(
51192 "Change requires confirmation",
51193 action.result.errorMsg,
51198 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
51208 Roo.callback(o.failure, o.scope, [this, action]);
51209 // show an error message if no failed handler is set..
51210 if (!this.hasListener('actionfailed')) {
51211 Roo.MessageBox.alert("Error",
51212 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
51213 action.result.errorMsg :
51214 "Saving Failed, please check your entries or try again"
51218 this.fireEvent('actionfailed', this, action);
51224 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
51225 * @param {String} id The value to search for
51228 findField : function(id){
51229 var field = this.items.get(id);
51231 this.items.each(function(f){
51232 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
51238 return field || null;
51242 * Add a secondary form to this one,
51243 * Used to provide tabbed forms. One form is primary, with hidden values
51244 * which mirror the elements from the other forms.
51246 * @param {Roo.form.Form} form to add.
51249 addForm : function(form)
51252 if (this.childForms.indexOf(form) > -1) {
51256 this.childForms.push(form);
51258 Roo.each(form.allItems, function (fe) {
51260 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
51261 if (this.findField(n)) { // already added..
51264 var add = new Roo.form.Hidden({
51267 add.render(this.el);
51274 * Mark fields in this form invalid in bulk.
51275 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
51276 * @return {BasicForm} this
51278 markInvalid : function(errors){
51279 if(errors instanceof Array){
51280 for(var i = 0, len = errors.length; i < len; i++){
51281 var fieldError = errors[i];
51282 var f = this.findField(fieldError.id);
51284 f.markInvalid(fieldError.msg);
51290 if(typeof errors[id] != 'function' && (field = this.findField(id))){
51291 field.markInvalid(errors[id]);
51295 Roo.each(this.childForms || [], function (f) {
51296 f.markInvalid(errors);
51303 * Set values for fields in this form in bulk.
51304 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
51305 * @return {BasicForm} this
51307 setValues : function(values){
51308 if(values instanceof Array){ // array of objects
51309 for(var i = 0, len = values.length; i < len; i++){
51311 var f = this.findField(v.id);
51313 f.setValue(v.value);
51314 if(this.trackResetOnLoad){
51315 f.originalValue = f.getValue();
51319 }else{ // object hash
51322 if(typeof values[id] != 'function' && (field = this.findField(id))){
51324 if (field.setFromData &&
51325 field.valueField &&
51326 field.displayField &&
51327 // combos' with local stores can
51328 // be queried via setValue()
51329 // to set their value..
51330 (field.store && !field.store.isLocal)
51334 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
51335 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
51336 field.setFromData(sd);
51339 field.setValue(values[id]);
51343 if(this.trackResetOnLoad){
51344 field.originalValue = field.getValue();
51349 this.resetHasChanged();
51352 Roo.each(this.childForms || [], function (f) {
51353 f.setValues(values);
51354 f.resetHasChanged();
51361 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
51362 * they are returned as an array.
51363 * @param {Boolean} asString
51366 getValues : function(asString){
51367 if (this.childForms) {
51368 // copy values from the child forms
51369 Roo.each(this.childForms, function (f) {
51370 this.setValues(f.getValues());
51376 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
51377 if(asString === true){
51380 return Roo.urlDecode(fs);
51384 * Returns the fields in this form as an object with key/value pairs.
51385 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
51388 getFieldValues : function(with_hidden)
51390 if (this.childForms) {
51391 // copy values from the child forms
51392 // should this call getFieldValues - probably not as we do not currently copy
51393 // hidden fields when we generate..
51394 Roo.each(this.childForms, function (f) {
51395 this.setValues(f.getValues());
51400 this.items.each(function(f){
51401 if (!f.getName()) {
51404 var v = f.getValue();
51405 if (f.inputType =='radio') {
51406 if (typeof(ret[f.getName()]) == 'undefined') {
51407 ret[f.getName()] = ''; // empty..
51410 if (!f.el.dom.checked) {
51414 v = f.el.dom.value;
51418 // not sure if this supported any more..
51419 if ((typeof(v) == 'object') && f.getRawValue) {
51420 v = f.getRawValue() ; // dates..
51422 // combo boxes where name != hiddenName...
51423 if (f.name != f.getName()) {
51424 ret[f.name] = f.getRawValue();
51426 ret[f.getName()] = v;
51433 * Clears all invalid messages in this form.
51434 * @return {BasicForm} this
51436 clearInvalid : function(){
51437 this.items.each(function(f){
51441 Roo.each(this.childForms || [], function (f) {
51450 * Resets this form.
51451 * @return {BasicForm} this
51453 reset : function(){
51454 this.items.each(function(f){
51458 Roo.each(this.childForms || [], function (f) {
51461 this.resetHasChanged();
51467 * Add Roo.form components to this form.
51468 * @param {Field} field1
51469 * @param {Field} field2 (optional)
51470 * @param {Field} etc (optional)
51471 * @return {BasicForm} this
51474 this.items.addAll(Array.prototype.slice.call(arguments, 0));
51480 * Removes a field from the items collection (does NOT remove its markup).
51481 * @param {Field} field
51482 * @return {BasicForm} this
51484 remove : function(field){
51485 this.items.remove(field);
51490 * Looks at the fields in this form, checks them for an id attribute,
51491 * and calls applyTo on the existing dom element with that id.
51492 * @return {BasicForm} this
51494 render : function(){
51495 this.items.each(function(f){
51496 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
51504 * Calls {@link Ext#apply} for all fields in this form with the passed object.
51505 * @param {Object} values
51506 * @return {BasicForm} this
51508 applyToFields : function(o){
51509 this.items.each(function(f){
51516 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
51517 * @param {Object} values
51518 * @return {BasicForm} this
51520 applyIfToFields : function(o){
51521 this.items.each(function(f){
51529 Roo.BasicForm = Roo.form.BasicForm;/*
51531 * Ext JS Library 1.1.1
51532 * Copyright(c) 2006-2007, Ext JS, LLC.
51534 * Originally Released Under LGPL - original licence link has changed is not relivant.
51537 * <script type="text/javascript">
51541 * @class Roo.form.Form
51542 * @extends Roo.form.BasicForm
51543 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
51545 * @param {Object} config Configuration options
51547 Roo.form.Form = function(config){
51549 if (config.items) {
51550 xitems = config.items;
51551 delete config.items;
51555 Roo.form.Form.superclass.constructor.call(this, null, config);
51556 this.url = this.url || this.action;
51558 this.root = new Roo.form.Layout(Roo.applyIf({
51562 this.active = this.root;
51564 * Array of all the buttons that have been added to this form via {@link addButton}
51568 this.allItems = [];
51571 * @event clientvalidation
51572 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
51573 * @param {Form} this
51574 * @param {Boolean} valid true if the form has passed client-side validation
51576 clientvalidation: true,
51579 * Fires when the form is rendered
51580 * @param {Roo.form.Form} form
51585 if (this.progressUrl) {
51586 // push a hidden field onto the list of fields..
51590 name : 'UPLOAD_IDENTIFIER'
51595 Roo.each(xitems, this.addxtype, this);
51601 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
51603 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
51606 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
51609 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
51611 buttonAlign:'center',
51614 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
51619 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
51620 * This property cascades to child containers if not set.
51625 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
51626 * fires a looping event with that state. This is required to bind buttons to the valid
51627 * state using the config value formBind:true on the button.
51629 monitorValid : false,
51632 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
51637 * @cfg {String} progressUrl - Url to return progress data
51640 progressUrl : false,
51643 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
51644 * fields are added and the column is closed. If no fields are passed the column remains open
51645 * until end() is called.
51646 * @param {Object} config The config to pass to the column
51647 * @param {Field} field1 (optional)
51648 * @param {Field} field2 (optional)
51649 * @param {Field} etc (optional)
51650 * @return Column The column container object
51652 column : function(c){
51653 var col = new Roo.form.Column(c);
51655 if(arguments.length > 1){ // duplicate code required because of Opera
51656 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
51663 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
51664 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
51665 * until end() is called.
51666 * @param {Object} config The config to pass to the fieldset
51667 * @param {Field} field1 (optional)
51668 * @param {Field} field2 (optional)
51669 * @param {Field} etc (optional)
51670 * @return FieldSet The fieldset container object
51672 fieldset : function(c){
51673 var fs = new Roo.form.FieldSet(c);
51675 if(arguments.length > 1){ // duplicate code required because of Opera
51676 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
51683 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
51684 * fields are added and the container is closed. If no fields are passed the container remains open
51685 * until end() is called.
51686 * @param {Object} config The config to pass to the Layout
51687 * @param {Field} field1 (optional)
51688 * @param {Field} field2 (optional)
51689 * @param {Field} etc (optional)
51690 * @return Layout The container object
51692 container : function(c){
51693 var l = new Roo.form.Layout(c);
51695 if(arguments.length > 1){ // duplicate code required because of Opera
51696 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
51703 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
51704 * @param {Object} container A Roo.form.Layout or subclass of Layout
51705 * @return {Form} this
51707 start : function(c){
51708 // cascade label info
51709 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
51710 this.active.stack.push(c);
51711 c.ownerCt = this.active;
51717 * Closes the current open container
51718 * @return {Form} this
51721 if(this.active == this.root){
51724 this.active = this.active.ownerCt;
51729 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
51730 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
51731 * as the label of the field.
51732 * @param {Field} field1
51733 * @param {Field} field2 (optional)
51734 * @param {Field} etc. (optional)
51735 * @return {Form} this
51738 this.active.stack.push.apply(this.active.stack, arguments);
51739 this.allItems.push.apply(this.allItems,arguments);
51741 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
51742 if(a[i].isFormField){
51747 Roo.form.Form.superclass.add.apply(this, r);
51757 * Find any element that has been added to a form, using it's ID or name
51758 * This can include framesets, columns etc. along with regular fields..
51759 * @param {String} id - id or name to find.
51761 * @return {Element} e - or false if nothing found.
51763 findbyId : function(id)
51769 Roo.each(this.allItems, function(f){
51770 if (f.id == id || f.name == id ){
51781 * Render this form into the passed container. This should only be called once!
51782 * @param {String/HTMLElement/Element} container The element this component should be rendered into
51783 * @return {Form} this
51785 render : function(ct)
51791 var o = this.autoCreate || {
51793 method : this.method || 'POST',
51794 id : this.id || Roo.id()
51796 this.initEl(ct.createChild(o));
51798 this.root.render(this.el);
51802 this.items.each(function(f){
51803 f.render('x-form-el-'+f.id);
51806 if(this.buttons.length > 0){
51807 // tables are required to maintain order and for correct IE layout
51808 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
51809 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
51810 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
51812 var tr = tb.getElementsByTagName('tr')[0];
51813 for(var i = 0, len = this.buttons.length; i < len; i++) {
51814 var b = this.buttons[i];
51815 var td = document.createElement('td');
51816 td.className = 'x-form-btn-td';
51817 b.render(tr.appendChild(td));
51820 if(this.monitorValid){ // initialize after render
51821 this.startMonitoring();
51823 this.fireEvent('rendered', this);
51828 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
51829 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
51830 * object or a valid Roo.DomHelper element config
51831 * @param {Function} handler The function called when the button is clicked
51832 * @param {Object} scope (optional) The scope of the handler function
51833 * @return {Roo.Button}
51835 addButton : function(config, handler, scope){
51839 minWidth: this.minButtonWidth,
51842 if(typeof config == "string"){
51845 Roo.apply(bc, config);
51847 var btn = new Roo.Button(null, bc);
51848 this.buttons.push(btn);
51853 * Adds a series of form elements (using the xtype property as the factory method.
51854 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
51855 * @param {Object} config
51858 addxtype : function()
51860 var ar = Array.prototype.slice.call(arguments, 0);
51862 for(var i = 0; i < ar.length; i++) {
51864 continue; // skip -- if this happends something invalid got sent, we
51865 // should ignore it, as basically that interface element will not show up
51866 // and that should be pretty obvious!!
51869 if (Roo.form[ar[i].xtype]) {
51871 var fe = Roo.factory(ar[i], Roo.form);
51877 fe.store.form = this;
51882 this.allItems.push(fe);
51883 if (fe.items && fe.addxtype) {
51884 fe.addxtype.apply(fe, fe.items);
51894 // console.log('adding ' + ar[i].xtype);
51896 if (ar[i].xtype == 'Button') {
51897 //console.log('adding button');
51898 //console.log(ar[i]);
51899 this.addButton(ar[i]);
51900 this.allItems.push(fe);
51904 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
51905 alert('end is not supported on xtype any more, use items');
51907 // //console.log('adding end');
51915 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
51916 * option "monitorValid"
51918 startMonitoring : function(){
51921 Roo.TaskMgr.start({
51922 run : this.bindHandler,
51923 interval : this.monitorPoll || 200,
51930 * Stops monitoring of the valid state of this form
51932 stopMonitoring : function(){
51933 this.bound = false;
51937 bindHandler : function(){
51939 return false; // stops binding
51942 this.items.each(function(f){
51943 if(!f.isValid(true)){
51948 for(var i = 0, len = this.buttons.length; i < len; i++){
51949 var btn = this.buttons[i];
51950 if(btn.formBind === true && btn.disabled === valid){
51951 btn.setDisabled(!valid);
51954 this.fireEvent('clientvalidation', this, valid);
51968 Roo.Form = Roo.form.Form;
51971 * Ext JS Library 1.1.1
51972 * Copyright(c) 2006-2007, Ext JS, LLC.
51974 * Originally Released Under LGPL - original licence link has changed is not relivant.
51977 * <script type="text/javascript">
51980 // as we use this in bootstrap.
51981 Roo.namespace('Roo.form');
51983 * @class Roo.form.Action
51984 * Internal Class used to handle form actions
51986 * @param {Roo.form.BasicForm} el The form element or its id
51987 * @param {Object} config Configuration options
51992 // define the action interface
51993 Roo.form.Action = function(form, options){
51995 this.options = options || {};
51998 * Client Validation Failed
52001 Roo.form.Action.CLIENT_INVALID = 'client';
52003 * Server Validation Failed
52006 Roo.form.Action.SERVER_INVALID = 'server';
52008 * Connect to Server Failed
52011 Roo.form.Action.CONNECT_FAILURE = 'connect';
52013 * Reading Data from Server Failed
52016 Roo.form.Action.LOAD_FAILURE = 'load';
52018 Roo.form.Action.prototype = {
52020 failureType : undefined,
52021 response : undefined,
52022 result : undefined,
52024 // interface method
52025 run : function(options){
52029 // interface method
52030 success : function(response){
52034 // interface method
52035 handleResponse : function(response){
52039 // default connection failure
52040 failure : function(response){
52042 this.response = response;
52043 this.failureType = Roo.form.Action.CONNECT_FAILURE;
52044 this.form.afterAction(this, false);
52047 processResponse : function(response){
52048 this.response = response;
52049 if(!response.responseText){
52052 this.result = this.handleResponse(response);
52053 return this.result;
52056 // utility functions used internally
52057 getUrl : function(appendParams){
52058 var url = this.options.url || this.form.url || this.form.el.dom.action;
52060 var p = this.getParams();
52062 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
52068 getMethod : function(){
52069 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
52072 getParams : function(){
52073 var bp = this.form.baseParams;
52074 var p = this.options.params;
52076 if(typeof p == "object"){
52077 p = Roo.urlEncode(Roo.applyIf(p, bp));
52078 }else if(typeof p == 'string' && bp){
52079 p += '&' + Roo.urlEncode(bp);
52082 p = Roo.urlEncode(bp);
52087 createCallback : function(){
52089 success: this.success,
52090 failure: this.failure,
52092 timeout: (this.form.timeout*1000),
52093 upload: this.form.fileUpload ? this.success : undefined
52098 Roo.form.Action.Submit = function(form, options){
52099 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
52102 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
52105 haveProgress : false,
52106 uploadComplete : false,
52108 // uploadProgress indicator.
52109 uploadProgress : function()
52111 if (!this.form.progressUrl) {
52115 if (!this.haveProgress) {
52116 Roo.MessageBox.progress("Uploading", "Uploading");
52118 if (this.uploadComplete) {
52119 Roo.MessageBox.hide();
52123 this.haveProgress = true;
52125 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
52127 var c = new Roo.data.Connection();
52129 url : this.form.progressUrl,
52134 success : function(req){
52135 //console.log(data);
52139 rdata = Roo.decode(req.responseText)
52141 Roo.log("Invalid data from server..");
52145 if (!rdata || !rdata.success) {
52147 Roo.MessageBox.alert(Roo.encode(rdata));
52150 var data = rdata.data;
52152 if (this.uploadComplete) {
52153 Roo.MessageBox.hide();
52158 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
52159 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
52162 this.uploadProgress.defer(2000,this);
52165 failure: function(data) {
52166 Roo.log('progress url failed ');
52177 // run get Values on the form, so it syncs any secondary forms.
52178 this.form.getValues();
52180 var o = this.options;
52181 var method = this.getMethod();
52182 var isPost = method == 'POST';
52183 if(o.clientValidation === false || this.form.isValid()){
52185 if (this.form.progressUrl) {
52186 this.form.findField('UPLOAD_IDENTIFIER').setValue(
52187 (new Date() * 1) + '' + Math.random());
52192 Roo.Ajax.request(Roo.apply(this.createCallback(), {
52193 form:this.form.el.dom,
52194 url:this.getUrl(!isPost),
52196 params:isPost ? this.getParams() : null,
52197 isUpload: this.form.fileUpload
52200 this.uploadProgress();
52202 }else if (o.clientValidation !== false){ // client validation failed
52203 this.failureType = Roo.form.Action.CLIENT_INVALID;
52204 this.form.afterAction(this, false);
52208 success : function(response)
52210 this.uploadComplete= true;
52211 if (this.haveProgress) {
52212 Roo.MessageBox.hide();
52216 var result = this.processResponse(response);
52217 if(result === true || result.success){
52218 this.form.afterAction(this, true);
52222 this.form.markInvalid(result.errors);
52223 this.failureType = Roo.form.Action.SERVER_INVALID;
52225 this.form.afterAction(this, false);
52227 failure : function(response)
52229 this.uploadComplete= true;
52230 if (this.haveProgress) {
52231 Roo.MessageBox.hide();
52234 this.response = response;
52235 this.failureType = Roo.form.Action.CONNECT_FAILURE;
52236 this.form.afterAction(this, false);
52239 handleResponse : function(response){
52240 if(this.form.errorReader){
52241 var rs = this.form.errorReader.read(response);
52244 for(var i = 0, len = rs.records.length; i < len; i++) {
52245 var r = rs.records[i];
52246 errors[i] = r.data;
52249 if(errors.length < 1){
52253 success : rs.success,
52259 ret = Roo.decode(response.responseText);
52263 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
52273 Roo.form.Action.Load = function(form, options){
52274 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
52275 this.reader = this.form.reader;
52278 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
52283 Roo.Ajax.request(Roo.apply(
52284 this.createCallback(), {
52285 method:this.getMethod(),
52286 url:this.getUrl(false),
52287 params:this.getParams()
52291 success : function(response){
52293 var result = this.processResponse(response);
52294 if(result === true || !result.success || !result.data){
52295 this.failureType = Roo.form.Action.LOAD_FAILURE;
52296 this.form.afterAction(this, false);
52299 this.form.clearInvalid();
52300 this.form.setValues(result.data);
52301 this.form.afterAction(this, true);
52304 handleResponse : function(response){
52305 if(this.form.reader){
52306 var rs = this.form.reader.read(response);
52307 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
52309 success : rs.success,
52313 return Roo.decode(response.responseText);
52317 Roo.form.Action.ACTION_TYPES = {
52318 'load' : Roo.form.Action.Load,
52319 'submit' : Roo.form.Action.Submit
52322 * Ext JS Library 1.1.1
52323 * Copyright(c) 2006-2007, Ext JS, LLC.
52325 * Originally Released Under LGPL - original licence link has changed is not relivant.
52328 * <script type="text/javascript">
52332 * @class Roo.form.Layout
52333 * @extends Roo.Component
52334 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
52336 * @param {Object} config Configuration options
52338 Roo.form.Layout = function(config){
52340 if (config.items) {
52341 xitems = config.items;
52342 delete config.items;
52344 Roo.form.Layout.superclass.constructor.call(this, config);
52346 Roo.each(xitems, this.addxtype, this);
52350 Roo.extend(Roo.form.Layout, Roo.Component, {
52352 * @cfg {String/Object} autoCreate
52353 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
52356 * @cfg {String/Object/Function} style
52357 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
52358 * a function which returns such a specification.
52361 * @cfg {String} labelAlign
52362 * Valid values are "left," "top" and "right" (defaults to "left")
52365 * @cfg {Number} labelWidth
52366 * Fixed width in pixels of all field labels (defaults to undefined)
52369 * @cfg {Boolean} clear
52370 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
52374 * @cfg {String} labelSeparator
52375 * The separator to use after field labels (defaults to ':')
52377 labelSeparator : ':',
52379 * @cfg {Boolean} hideLabels
52380 * True to suppress the display of field labels in this layout (defaults to false)
52382 hideLabels : false,
52385 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
52390 onRender : function(ct, position){
52391 if(this.el){ // from markup
52392 this.el = Roo.get(this.el);
52393 }else { // generate
52394 var cfg = this.getAutoCreate();
52395 this.el = ct.createChild(cfg, position);
52398 this.el.applyStyles(this.style);
52400 if(this.labelAlign){
52401 this.el.addClass('x-form-label-'+this.labelAlign);
52403 if(this.hideLabels){
52404 this.labelStyle = "display:none";
52405 this.elementStyle = "padding-left:0;";
52407 if(typeof this.labelWidth == 'number'){
52408 this.labelStyle = "width:"+this.labelWidth+"px;";
52409 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
52411 if(this.labelAlign == 'top'){
52412 this.labelStyle = "width:auto;";
52413 this.elementStyle = "padding-left:0;";
52416 var stack = this.stack;
52417 var slen = stack.length;
52419 if(!this.fieldTpl){
52420 var t = new Roo.Template(
52421 '<div class="x-form-item {5}">',
52422 '<label for="{0}" style="{2}">{1}{4}</label>',
52423 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
52425 '</div><div class="x-form-clear-left"></div>'
52427 t.disableFormats = true;
52429 Roo.form.Layout.prototype.fieldTpl = t;
52431 for(var i = 0; i < slen; i++) {
52432 if(stack[i].isFormField){
52433 this.renderField(stack[i]);
52435 this.renderComponent(stack[i]);
52440 this.el.createChild({cls:'x-form-clear'});
52445 renderField : function(f){
52446 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
52449 f.labelStyle||this.labelStyle||'', //2
52450 this.elementStyle||'', //3
52451 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
52452 f.itemCls||this.itemCls||'' //5
52453 ], true).getPrevSibling());
52457 renderComponent : function(c){
52458 c.render(c.isLayout ? this.el : this.el.createChild());
52461 * Adds a object form elements (using the xtype property as the factory method.)
52462 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
52463 * @param {Object} config
52465 addxtype : function(o)
52467 // create the lement.
52468 o.form = this.form;
52469 var fe = Roo.factory(o, Roo.form);
52470 this.form.allItems.push(fe);
52471 this.stack.push(fe);
52473 if (fe.isFormField) {
52474 this.form.items.add(fe);
52482 * @class Roo.form.Column
52483 * @extends Roo.form.Layout
52484 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
52486 * @param {Object} config Configuration options
52488 Roo.form.Column = function(config){
52489 Roo.form.Column.superclass.constructor.call(this, config);
52492 Roo.extend(Roo.form.Column, Roo.form.Layout, {
52494 * @cfg {Number/String} width
52495 * The fixed width of the column in pixels or CSS value (defaults to "auto")
52498 * @cfg {String/Object} autoCreate
52499 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
52503 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
52506 onRender : function(ct, position){
52507 Roo.form.Column.superclass.onRender.call(this, ct, position);
52509 this.el.setWidth(this.width);
52516 * @class Roo.form.Row
52517 * @extends Roo.form.Layout
52518 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
52520 * @param {Object} config Configuration options
52524 Roo.form.Row = function(config){
52525 Roo.form.Row.superclass.constructor.call(this, config);
52528 Roo.extend(Roo.form.Row, Roo.form.Layout, {
52530 * @cfg {Number/String} width
52531 * The fixed width of the column in pixels or CSS value (defaults to "auto")
52534 * @cfg {Number/String} height
52535 * The fixed height of the column in pixels or CSS value (defaults to "auto")
52537 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
52541 onRender : function(ct, position){
52542 //console.log('row render');
52544 var t = new Roo.Template(
52545 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
52546 '<label for="{0}" style="{2}">{1}{4}</label>',
52547 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
52551 t.disableFormats = true;
52553 Roo.form.Layout.prototype.rowTpl = t;
52555 this.fieldTpl = this.rowTpl;
52557 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
52558 var labelWidth = 100;
52560 if ((this.labelAlign != 'top')) {
52561 if (typeof this.labelWidth == 'number') {
52562 labelWidth = this.labelWidth
52564 this.padWidth = 20 + labelWidth;
52568 Roo.form.Column.superclass.onRender.call(this, ct, position);
52570 this.el.setWidth(this.width);
52573 this.el.setHeight(this.height);
52578 renderField : function(f){
52579 f.fieldEl = this.fieldTpl.append(this.el, [
52580 f.id, f.fieldLabel,
52581 f.labelStyle||this.labelStyle||'',
52582 this.elementStyle||'',
52583 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
52584 f.itemCls||this.itemCls||'',
52585 f.width ? f.width + this.padWidth : 160 + this.padWidth
52592 * @class Roo.form.FieldSet
52593 * @extends Roo.form.Layout
52594 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
52596 * @param {Object} config Configuration options
52598 Roo.form.FieldSet = function(config){
52599 Roo.form.FieldSet.superclass.constructor.call(this, config);
52602 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
52604 * @cfg {String} legend
52605 * The text to display as the legend for the FieldSet (defaults to '')
52608 * @cfg {String/Object} autoCreate
52609 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
52613 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
52616 onRender : function(ct, position){
52617 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
52619 this.setLegend(this.legend);
52624 setLegend : function(text){
52626 this.el.child('legend').update(text);
52631 * Ext JS Library 1.1.1
52632 * Copyright(c) 2006-2007, Ext JS, LLC.
52634 * Originally Released Under LGPL - original licence link has changed is not relivant.
52637 * <script type="text/javascript">
52640 * @class Roo.form.VTypes
52641 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
52644 Roo.form.VTypes = function(){
52645 // closure these in so they are only created once.
52646 var alpha = /^[a-zA-Z_]+$/;
52647 var alphanum = /^[a-zA-Z0-9_]+$/;
52648 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
52649 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
52651 // All these messages and functions are configurable
52654 * The function used to validate email addresses
52655 * @param {String} value The email address
52657 'email' : function(v){
52658 return email.test(v);
52661 * The error text to display when the email validation function returns false
52664 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
52666 * The keystroke filter mask to be applied on email input
52669 'emailMask' : /[a-z0-9_\.\-@]/i,
52672 * The function used to validate URLs
52673 * @param {String} value The URL
52675 'url' : function(v){
52676 return url.test(v);
52679 * The error text to display when the url validation function returns false
52682 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
52685 * The function used to validate alpha values
52686 * @param {String} value The value
52688 'alpha' : function(v){
52689 return alpha.test(v);
52692 * The error text to display when the alpha validation function returns false
52695 'alphaText' : 'This field should only contain letters and _',
52697 * The keystroke filter mask to be applied on alpha input
52700 'alphaMask' : /[a-z_]/i,
52703 * The function used to validate alphanumeric values
52704 * @param {String} value The value
52706 'alphanum' : function(v){
52707 return alphanum.test(v);
52710 * The error text to display when the alphanumeric validation function returns false
52713 'alphanumText' : 'This field should only contain letters, numbers and _',
52715 * The keystroke filter mask to be applied on alphanumeric input
52718 'alphanumMask' : /[a-z0-9_]/i
52720 }();//<script type="text/javascript">
52723 * @class Roo.form.FCKeditor
52724 * @extends Roo.form.TextArea
52725 * Wrapper around the FCKEditor http://www.fckeditor.net
52727 * Creates a new FCKeditor
52728 * @param {Object} config Configuration options
52730 Roo.form.FCKeditor = function(config){
52731 Roo.form.FCKeditor.superclass.constructor.call(this, config);
52734 * @event editorinit
52735 * Fired when the editor is initialized - you can add extra handlers here..
52736 * @param {FCKeditor} this
52737 * @param {Object} the FCK object.
52744 Roo.form.FCKeditor.editors = { };
52745 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
52747 //defaultAutoCreate : {
52748 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
52752 * @cfg {Object} fck options - see fck manual for details.
52757 * @cfg {Object} fck toolbar set (Basic or Default)
52759 toolbarSet : 'Basic',
52761 * @cfg {Object} fck BasePath
52763 basePath : '/fckeditor/',
52771 onRender : function(ct, position)
52774 this.defaultAutoCreate = {
52776 style:"width:300px;height:60px;",
52777 autocomplete: "new-password"
52780 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
52783 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
52784 if(this.preventScrollbars){
52785 this.el.setStyle("overflow", "hidden");
52787 this.el.setHeight(this.growMin);
52790 //console.log('onrender' + this.getId() );
52791 Roo.form.FCKeditor.editors[this.getId()] = this;
52794 this.replaceTextarea() ;
52798 getEditor : function() {
52799 return this.fckEditor;
52802 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
52803 * @param {Mixed} value The value to set
52807 setValue : function(value)
52809 //console.log('setValue: ' + value);
52811 if(typeof(value) == 'undefined') { // not sure why this is happending...
52814 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
52816 //if(!this.el || !this.getEditor()) {
52817 // this.value = value;
52818 //this.setValue.defer(100,this,[value]);
52822 if(!this.getEditor()) {
52826 this.getEditor().SetData(value);
52833 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
52834 * @return {Mixed} value The field value
52836 getValue : function()
52839 if (this.frame && this.frame.dom.style.display == 'none') {
52840 return Roo.form.FCKeditor.superclass.getValue.call(this);
52843 if(!this.el || !this.getEditor()) {
52845 // this.getValue.defer(100,this);
52850 var value=this.getEditor().GetData();
52851 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
52852 return Roo.form.FCKeditor.superclass.getValue.call(this);
52858 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
52859 * @return {Mixed} value The field value
52861 getRawValue : function()
52863 if (this.frame && this.frame.dom.style.display == 'none') {
52864 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
52867 if(!this.el || !this.getEditor()) {
52868 //this.getRawValue.defer(100,this);
52875 var value=this.getEditor().GetData();
52876 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
52877 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
52881 setSize : function(w,h) {
52885 //if (this.frame && this.frame.dom.style.display == 'none') {
52886 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
52889 //if(!this.el || !this.getEditor()) {
52890 // this.setSize.defer(100,this, [w,h]);
52896 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
52898 this.frame.dom.setAttribute('width', w);
52899 this.frame.dom.setAttribute('height', h);
52900 this.frame.setSize(w,h);
52904 toggleSourceEdit : function(value) {
52908 this.el.dom.style.display = value ? '' : 'none';
52909 this.frame.dom.style.display = value ? 'none' : '';
52914 focus: function(tag)
52916 if (this.frame.dom.style.display == 'none') {
52917 return Roo.form.FCKeditor.superclass.focus.call(this);
52919 if(!this.el || !this.getEditor()) {
52920 this.focus.defer(100,this, [tag]);
52927 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
52928 this.getEditor().Focus();
52930 if (!this.getEditor().Selection.GetSelection()) {
52931 this.focus.defer(100,this, [tag]);
52936 var r = this.getEditor().EditorDocument.createRange();
52937 r.setStart(tgs[0],0);
52938 r.setEnd(tgs[0],0);
52939 this.getEditor().Selection.GetSelection().removeAllRanges();
52940 this.getEditor().Selection.GetSelection().addRange(r);
52941 this.getEditor().Focus();
52948 replaceTextarea : function()
52950 if ( document.getElementById( this.getId() + '___Frame' ) ) {
52953 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
52955 // We must check the elements firstly using the Id and then the name.
52956 var oTextarea = document.getElementById( this.getId() );
52958 var colElementsByName = document.getElementsByName( this.getId() ) ;
52960 oTextarea.style.display = 'none' ;
52962 if ( oTextarea.tabIndex ) {
52963 this.TabIndex = oTextarea.tabIndex ;
52966 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
52967 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
52968 this.frame = Roo.get(this.getId() + '___Frame')
52971 _getConfigHtml : function()
52975 for ( var o in this.fckconfig ) {
52976 sConfig += sConfig.length > 0 ? '&' : '';
52977 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
52980 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
52984 _getIFrameHtml : function()
52986 var sFile = 'fckeditor.html' ;
52987 /* no idea what this is about..
52990 if ( (/fcksource=true/i).test( window.top.location.search ) )
52991 sFile = 'fckeditor.original.html' ;
52996 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
52997 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
53000 var html = '<iframe id="' + this.getId() +
53001 '___Frame" src="' + sLink +
53002 '" width="' + this.width +
53003 '" height="' + this.height + '"' +
53004 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
53005 ' frameborder="0" scrolling="no"></iframe>' ;
53010 _insertHtmlBefore : function( html, element )
53012 if ( element.insertAdjacentHTML ) {
53014 element.insertAdjacentHTML( 'beforeBegin', html ) ;
53016 var oRange = document.createRange() ;
53017 oRange.setStartBefore( element ) ;
53018 var oFragment = oRange.createContextualFragment( html );
53019 element.parentNode.insertBefore( oFragment, element ) ;
53032 //Roo.reg('fckeditor', Roo.form.FCKeditor);
53034 function FCKeditor_OnComplete(editorInstance){
53035 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
53036 f.fckEditor = editorInstance;
53037 //console.log("loaded");
53038 f.fireEvent('editorinit', f, editorInstance);
53058 //<script type="text/javascript">
53060 * @class Roo.form.GridField
53061 * @extends Roo.form.Field
53062 * Embed a grid (or editable grid into a form)
53065 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
53067 * xgrid.store = Roo.data.Store
53068 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
53069 * xgrid.store.reader = Roo.data.JsonReader
53073 * Creates a new GridField
53074 * @param {Object} config Configuration options
53076 Roo.form.GridField = function(config){
53077 Roo.form.GridField.superclass.constructor.call(this, config);
53081 Roo.extend(Roo.form.GridField, Roo.form.Field, {
53083 * @cfg {Number} width - used to restrict width of grid..
53087 * @cfg {Number} height - used to restrict height of grid..
53091 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
53097 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
53098 * {tag: "input", type: "checkbox", autocomplete: "off"})
53100 // defaultAutoCreate : { tag: 'div' },
53101 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
53103 * @cfg {String} addTitle Text to include for adding a title.
53107 onResize : function(){
53108 Roo.form.Field.superclass.onResize.apply(this, arguments);
53111 initEvents : function(){
53112 // Roo.form.Checkbox.superclass.initEvents.call(this);
53113 // has no events...
53118 getResizeEl : function(){
53122 getPositionEl : function(){
53127 onRender : function(ct, position){
53129 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
53130 var style = this.style;
53133 Roo.form.GridField.superclass.onRender.call(this, ct, position);
53134 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
53135 this.viewEl = this.wrap.createChild({ tag: 'div' });
53137 this.viewEl.applyStyles(style);
53140 this.viewEl.setWidth(this.width);
53143 this.viewEl.setHeight(this.height);
53145 //if(this.inputValue !== undefined){
53146 //this.setValue(this.value);
53149 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
53152 this.grid.render();
53153 this.grid.getDataSource().on('remove', this.refreshValue, this);
53154 this.grid.getDataSource().on('update', this.refreshValue, this);
53155 this.grid.on('afteredit', this.refreshValue, this);
53161 * Sets the value of the item.
53162 * @param {String} either an object or a string..
53164 setValue : function(v){
53166 v = v || []; // empty set..
53167 // this does not seem smart - it really only affects memoryproxy grids..
53168 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
53169 var ds = this.grid.getDataSource();
53170 // assumes a json reader..
53172 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
53173 ds.loadData( data);
53175 // clear selection so it does not get stale.
53176 if (this.grid.sm) {
53177 this.grid.sm.clearSelections();
53180 Roo.form.GridField.superclass.setValue.call(this, v);
53181 this.refreshValue();
53182 // should load data in the grid really....
53186 refreshValue: function() {
53188 this.grid.getDataSource().each(function(r) {
53191 this.el.dom.value = Roo.encode(val);
53199 * Ext JS Library 1.1.1
53200 * Copyright(c) 2006-2007, Ext JS, LLC.
53202 * Originally Released Under LGPL - original licence link has changed is not relivant.
53205 * <script type="text/javascript">
53208 * @class Roo.form.DisplayField
53209 * @extends Roo.form.Field
53210 * A generic Field to display non-editable data.
53211 * @cfg {Boolean} closable (true|false) default false
53213 * Creates a new Display Field item.
53214 * @param {Object} config Configuration options
53216 Roo.form.DisplayField = function(config){
53217 Roo.form.DisplayField.superclass.constructor.call(this, config);
53222 * Fires after the click the close btn
53223 * @param {Roo.form.DisplayField} this
53229 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
53230 inputType: 'hidden',
53236 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
53238 focusClass : undefined,
53240 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
53242 fieldClass: 'x-form-field',
53245 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
53247 valueRenderer: undefined,
53251 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
53252 * {tag: "input", type: "checkbox", autocomplete: "off"})
53255 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
53259 onResize : function(){
53260 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
53264 initEvents : function(){
53265 // Roo.form.Checkbox.superclass.initEvents.call(this);
53266 // has no events...
53269 this.closeEl.on('click', this.onClose, this);
53275 getResizeEl : function(){
53279 getPositionEl : function(){
53284 onRender : function(ct, position){
53286 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
53287 //if(this.inputValue !== undefined){
53288 this.wrap = this.el.wrap();
53290 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
53293 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
53296 if (this.bodyStyle) {
53297 this.viewEl.applyStyles(this.bodyStyle);
53299 //this.viewEl.setStyle('padding', '2px');
53301 this.setValue(this.value);
53306 initValue : Roo.emptyFn,
53311 onClick : function(){
53316 * Sets the checked state of the checkbox.
53317 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
53319 setValue : function(v){
53321 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
53322 // this might be called before we have a dom element..
53323 if (!this.viewEl) {
53326 this.viewEl.dom.innerHTML = html;
53327 Roo.form.DisplayField.superclass.setValue.call(this, v);
53331 onClose : function(e)
53333 e.preventDefault();
53335 this.fireEvent('close', this);
53344 * @class Roo.form.DayPicker
53345 * @extends Roo.form.Field
53346 * A Day picker show [M] [T] [W] ....
53348 * Creates a new Day Picker
53349 * @param {Object} config Configuration options
53351 Roo.form.DayPicker= function(config){
53352 Roo.form.DayPicker.superclass.constructor.call(this, config);
53356 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
53358 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
53360 focusClass : undefined,
53362 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
53364 fieldClass: "x-form-field",
53367 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
53368 * {tag: "input", type: "checkbox", autocomplete: "off"})
53370 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
53373 actionMode : 'viewEl',
53377 inputType : 'hidden',
53380 inputElement: false, // real input element?
53381 basedOn: false, // ????
53383 isFormField: true, // not sure where this is needed!!!!
53385 onResize : function(){
53386 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
53387 if(!this.boxLabel){
53388 this.el.alignTo(this.wrap, 'c-c');
53392 initEvents : function(){
53393 Roo.form.Checkbox.superclass.initEvents.call(this);
53394 this.el.on("click", this.onClick, this);
53395 this.el.on("change", this.onClick, this);
53399 getResizeEl : function(){
53403 getPositionEl : function(){
53409 onRender : function(ct, position){
53410 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
53412 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
53414 var r1 = '<table><tr>';
53415 var r2 = '<tr class="x-form-daypick-icons">';
53416 for (var i=0; i < 7; i++) {
53417 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
53418 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
53421 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
53422 viewEl.select('img').on('click', this.onClick, this);
53423 this.viewEl = viewEl;
53426 // this will not work on Chrome!!!
53427 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
53428 this.el.on('propertychange', this.setFromHidden, this); //ie
53436 initValue : Roo.emptyFn,
53439 * Returns the checked state of the checkbox.
53440 * @return {Boolean} True if checked, else false
53442 getValue : function(){
53443 return this.el.dom.value;
53448 onClick : function(e){
53449 //this.setChecked(!this.checked);
53450 Roo.get(e.target).toggleClass('x-menu-item-checked');
53451 this.refreshValue();
53452 //if(this.el.dom.checked != this.checked){
53453 // this.setValue(this.el.dom.checked);
53458 refreshValue : function()
53461 this.viewEl.select('img',true).each(function(e,i,n) {
53462 val += e.is(".x-menu-item-checked") ? String(n) : '';
53464 this.setValue(val, true);
53468 * Sets the checked state of the checkbox.
53469 * On is always based on a string comparison between inputValue and the param.
53470 * @param {Boolean/String} value - the value to set
53471 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
53473 setValue : function(v,suppressEvent){
53474 if (!this.el.dom) {
53477 var old = this.el.dom.value ;
53478 this.el.dom.value = v;
53479 if (suppressEvent) {
53483 // update display..
53484 this.viewEl.select('img',true).each(function(e,i,n) {
53486 var on = e.is(".x-menu-item-checked");
53487 var newv = v.indexOf(String(n)) > -1;
53489 e.toggleClass('x-menu-item-checked');
53495 this.fireEvent('change', this, v, old);
53500 // handle setting of hidden value by some other method!!?!?
53501 setFromHidden: function()
53506 //console.log("SET FROM HIDDEN");
53507 //alert('setFrom hidden');
53508 this.setValue(this.el.dom.value);
53511 onDestroy : function()
53514 Roo.get(this.viewEl).remove();
53517 Roo.form.DayPicker.superclass.onDestroy.call(this);
53521 * RooJS Library 1.1.1
53522 * Copyright(c) 2008-2011 Alan Knowles
53529 * @class Roo.form.ComboCheck
53530 * @extends Roo.form.ComboBox
53531 * A combobox for multiple select items.
53533 * FIXME - could do with a reset button..
53536 * Create a new ComboCheck
53537 * @param {Object} config Configuration options
53539 Roo.form.ComboCheck = function(config){
53540 Roo.form.ComboCheck.superclass.constructor.call(this, config);
53541 // should verify some data...
53543 // hiddenName = required..
53544 // displayField = required
53545 // valudField == required
53546 var req= [ 'hiddenName', 'displayField', 'valueField' ];
53548 Roo.each(req, function(e) {
53549 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
53550 throw "Roo.form.ComboCheck : missing value for: " + e;
53557 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
53562 selectedClass: 'x-menu-item-checked',
53565 onRender : function(ct, position){
53571 var cls = 'x-combo-list';
53574 this.tpl = new Roo.Template({
53575 html : '<div class="'+cls+'-item x-menu-check-item">' +
53576 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
53577 '<span>{' + this.displayField + '}</span>' +
53584 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
53585 this.view.singleSelect = false;
53586 this.view.multiSelect = true;
53587 this.view.toggleSelect = true;
53588 this.pageTb.add(new Roo.Toolbar.Fill(), {
53591 handler: function()
53598 onViewOver : function(e, t){
53604 onViewClick : function(doFocus,index){
53608 select: function () {
53609 //Roo.log("SELECT CALLED");
53612 selectByValue : function(xv, scrollIntoView){
53613 var ar = this.getValueArray();
53616 Roo.each(ar, function(v) {
53617 if(v === undefined || v === null){
53620 var r = this.findRecord(this.valueField, v);
53622 sels.push(this.store.indexOf(r))
53626 this.view.select(sels);
53632 onSelect : function(record, index){
53633 // Roo.log("onselect Called");
53634 // this is only called by the clear button now..
53635 this.view.clearSelections();
53636 this.setValue('[]');
53637 if (this.value != this.valueBefore) {
53638 this.fireEvent('change', this, this.value, this.valueBefore);
53639 this.valueBefore = this.value;
53642 getValueArray : function()
53647 //Roo.log(this.value);
53648 if (typeof(this.value) == 'undefined') {
53651 var ar = Roo.decode(this.value);
53652 return ar instanceof Array ? ar : []; //?? valid?
53655 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
53660 expand : function ()
53663 Roo.form.ComboCheck.superclass.expand.call(this);
53664 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
53665 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
53670 collapse : function(){
53671 Roo.form.ComboCheck.superclass.collapse.call(this);
53672 var sl = this.view.getSelectedIndexes();
53673 var st = this.store;
53677 Roo.each(sl, function(i) {
53679 nv.push(r.get(this.valueField));
53681 this.setValue(Roo.encode(nv));
53682 if (this.value != this.valueBefore) {
53684 this.fireEvent('change', this, this.value, this.valueBefore);
53685 this.valueBefore = this.value;
53690 setValue : function(v){
53694 var vals = this.getValueArray();
53696 Roo.each(vals, function(k) {
53697 var r = this.findRecord(this.valueField, k);
53699 tv.push(r.data[this.displayField]);
53700 }else if(this.valueNotFoundText !== undefined){
53701 tv.push( this.valueNotFoundText );
53706 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
53707 this.hiddenField.value = v;
53713 * Ext JS Library 1.1.1
53714 * Copyright(c) 2006-2007, Ext JS, LLC.
53716 * Originally Released Under LGPL - original licence link has changed is not relivant.
53719 * <script type="text/javascript">
53723 * @class Roo.form.Signature
53724 * @extends Roo.form.Field
53728 * @param {Object} config Configuration options
53731 Roo.form.Signature = function(config){
53732 Roo.form.Signature.superclass.constructor.call(this, config);
53734 this.addEvents({// not in used??
53737 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
53738 * @param {Roo.form.Signature} combo This combo box
53743 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
53744 * @param {Roo.form.ComboBox} combo This combo box
53745 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
53751 Roo.extend(Roo.form.Signature, Roo.form.Field, {
53753 * @cfg {Object} labels Label to use when rendering a form.
53757 * confirm : "Confirm"
53762 confirm : "Confirm"
53765 * @cfg {Number} width The signature panel width (defaults to 300)
53769 * @cfg {Number} height The signature panel height (defaults to 100)
53773 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
53775 allowBlank : false,
53778 // {Object} signPanel The signature SVG panel element (defaults to {})
53780 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
53781 isMouseDown : false,
53782 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
53783 isConfirmed : false,
53784 // {String} signatureTmp SVG mapping string (defaults to empty string)
53788 defaultAutoCreate : { // modified by initCompnoent..
53794 onRender : function(ct, position){
53796 Roo.form.Signature.superclass.onRender.call(this, ct, position);
53798 this.wrap = this.el.wrap({
53799 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
53802 this.createToolbar(this);
53803 this.signPanel = this.wrap.createChild({
53805 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
53809 this.svgID = Roo.id();
53810 this.svgEl = this.signPanel.createChild({
53811 xmlns : 'http://www.w3.org/2000/svg',
53813 id : this.svgID + "-svg",
53815 height: this.height,
53816 viewBox: '0 0 '+this.width+' '+this.height,
53820 id: this.svgID + "-svg-r",
53822 height: this.height,
53827 id: this.svgID + "-svg-l",
53829 y1: (this.height*0.8), // start set the line in 80% of height
53830 x2: this.width, // end
53831 y2: (this.height*0.8), // end set the line in 80% of height
53833 'stroke-width': "1",
53834 'stroke-dasharray': "3",
53835 'shape-rendering': "crispEdges",
53836 'pointer-events': "none"
53840 id: this.svgID + "-svg-p",
53842 'stroke-width': "3",
53844 'pointer-events': 'none'
53849 this.svgBox = this.svgEl.dom.getScreenCTM();
53851 createSVG : function(){
53852 var svg = this.signPanel;
53853 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
53856 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
53857 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
53858 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
53859 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
53860 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
53861 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
53862 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
53865 isTouchEvent : function(e){
53866 return e.type.match(/^touch/);
53868 getCoords : function (e) {
53869 var pt = this.svgEl.dom.createSVGPoint();
53872 if (this.isTouchEvent(e)) {
53873 pt.x = e.targetTouches[0].clientX;
53874 pt.y = e.targetTouches[0].clientY;
53876 var a = this.svgEl.dom.getScreenCTM();
53877 var b = a.inverse();
53878 var mx = pt.matrixTransform(b);
53879 return mx.x + ',' + mx.y;
53881 //mouse event headler
53882 down : function (e) {
53883 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
53884 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
53886 this.isMouseDown = true;
53888 e.preventDefault();
53890 move : function (e) {
53891 if (this.isMouseDown) {
53892 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
53893 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
53896 e.preventDefault();
53898 up : function (e) {
53899 this.isMouseDown = false;
53900 var sp = this.signatureTmp.split(' ');
53903 if(!sp[sp.length-2].match(/^L/)){
53907 this.signatureTmp = sp.join(" ");
53910 if(this.getValue() != this.signatureTmp){
53911 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
53912 this.isConfirmed = false;
53914 e.preventDefault();
53918 * Protected method that will not generally be called directly. It
53919 * is called when the editor creates its toolbar. Override this method if you need to
53920 * add custom toolbar buttons.
53921 * @param {HtmlEditor} editor
53923 createToolbar : function(editor){
53924 function btn(id, toggle, handler){
53925 var xid = fid + '-'+ id ;
53929 cls : 'x-btn-icon x-edit-'+id,
53930 enableToggle:toggle !== false,
53931 scope: editor, // was editor...
53932 handler:handler||editor.relayBtnCmd,
53933 clickEvent:'mousedown',
53934 tooltip: etb.buttonTips[id] || undefined, ///tips ???
53940 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
53944 cls : ' x-signature-btn x-signature-'+id,
53945 scope: editor, // was editor...
53946 handler: this.reset,
53947 clickEvent:'mousedown',
53948 text: this.labels.clear
53955 cls : ' x-signature-btn x-signature-'+id,
53956 scope: editor, // was editor...
53957 handler: this.confirmHandler,
53958 clickEvent:'mousedown',
53959 text: this.labels.confirm
53966 * when user is clicked confirm then show this image.....
53968 * @return {String} Image Data URI
53970 getImageDataURI : function(){
53971 var svg = this.svgEl.dom.parentNode.innerHTML;
53972 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
53977 * @return {Boolean} this.isConfirmed
53979 getConfirmed : function(){
53980 return this.isConfirmed;
53984 * @return {Number} this.width
53986 getWidth : function(){
53991 * @return {Number} this.height
53993 getHeight : function(){
53994 return this.height;
53997 getSignature : function(){
53998 return this.signatureTmp;
54001 reset : function(){
54002 this.signatureTmp = '';
54003 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
54004 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
54005 this.isConfirmed = false;
54006 Roo.form.Signature.superclass.reset.call(this);
54008 setSignature : function(s){
54009 this.signatureTmp = s;
54010 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
54011 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
54013 this.isConfirmed = false;
54014 Roo.form.Signature.superclass.reset.call(this);
54017 // Roo.log(this.signPanel.dom.contentWindow.up())
54020 setConfirmed : function(){
54024 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
54027 confirmHandler : function(){
54028 if(!this.getSignature()){
54032 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
54033 this.setValue(this.getSignature());
54034 this.isConfirmed = true;
54036 this.fireEvent('confirm', this);
54039 // Subclasses should provide the validation implementation by overriding this
54040 validateValue : function(value){
54041 if(this.allowBlank){
54045 if(this.isConfirmed){
54052 * Ext JS Library 1.1.1
54053 * Copyright(c) 2006-2007, Ext JS, LLC.
54055 * Originally Released Under LGPL - original licence link has changed is not relivant.
54058 * <script type="text/javascript">
54063 * @class Roo.form.ComboBox
54064 * @extends Roo.form.TriggerField
54065 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
54067 * Create a new ComboBox.
54068 * @param {Object} config Configuration options
54070 Roo.form.Select = function(config){
54071 Roo.form.Select.superclass.constructor.call(this, config);
54075 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
54077 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
54080 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
54081 * rendering into an Roo.Editor, defaults to false)
54084 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
54085 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
54088 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
54091 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
54092 * the dropdown list (defaults to undefined, with no header element)
54096 * @cfg {String/Roo.Template} tpl The template to use to render the output
54100 defaultAutoCreate : {tag: "select" },
54102 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
54104 listWidth: undefined,
54106 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
54107 * mode = 'remote' or 'text' if mode = 'local')
54109 displayField: undefined,
54111 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
54112 * mode = 'remote' or 'value' if mode = 'local').
54113 * Note: use of a valueField requires the user make a selection
54114 * in order for a value to be mapped.
54116 valueField: undefined,
54120 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
54121 * field's data value (defaults to the underlying DOM element's name)
54123 hiddenName: undefined,
54125 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
54129 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
54131 selectedClass: 'x-combo-selected',
54133 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
54134 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
54135 * which displays a downward arrow icon).
54137 triggerClass : 'x-form-arrow-trigger',
54139 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
54143 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
54144 * anchor positions (defaults to 'tl-bl')
54146 listAlign: 'tl-bl?',
54148 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
54152 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
54153 * query specified by the allQuery config option (defaults to 'query')
54155 triggerAction: 'query',
54157 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
54158 * (defaults to 4, does not apply if editable = false)
54162 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
54163 * delay (typeAheadDelay) if it matches a known value (defaults to false)
54167 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
54168 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
54172 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
54173 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
54177 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
54178 * when editable = true (defaults to false)
54180 selectOnFocus:false,
54182 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
54184 queryParam: 'query',
54186 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
54187 * when mode = 'remote' (defaults to 'Loading...')
54189 loadingText: 'Loading...',
54191 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
54195 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
54199 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
54200 * traditional select (defaults to true)
54204 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
54208 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
54212 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
54213 * listWidth has a higher value)
54217 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
54218 * allow the user to set arbitrary text into the field (defaults to false)
54220 forceSelection:false,
54222 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
54223 * if typeAhead = true (defaults to 250)
54225 typeAheadDelay : 250,
54227 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
54228 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
54230 valueNotFoundText : undefined,
54233 * @cfg {String} defaultValue The value displayed after loading the store.
54238 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
54240 blockFocus : false,
54243 * @cfg {Boolean} disableClear Disable showing of clear button.
54245 disableClear : false,
54247 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
54249 alwaysQuery : false,
54255 // element that contains real text value.. (when hidden is used..)
54258 onRender : function(ct, position){
54259 Roo.form.Field.prototype.onRender.call(this, ct, position);
54262 this.store.on('beforeload', this.onBeforeLoad, this);
54263 this.store.on('load', this.onLoad, this);
54264 this.store.on('loadexception', this.onLoadException, this);
54265 this.store.load({});
54273 initEvents : function(){
54274 //Roo.form.ComboBox.superclass.initEvents.call(this);
54278 onDestroy : function(){
54281 this.store.un('beforeload', this.onBeforeLoad, this);
54282 this.store.un('load', this.onLoad, this);
54283 this.store.un('loadexception', this.onLoadException, this);
54285 //Roo.form.ComboBox.superclass.onDestroy.call(this);
54289 fireKey : function(e){
54290 if(e.isNavKeyPress() && !this.list.isVisible()){
54291 this.fireEvent("specialkey", this, e);
54296 onResize: function(w, h){
54304 * Allow or prevent the user from directly editing the field text. If false is passed,
54305 * the user will only be able to select from the items defined in the dropdown list. This method
54306 * is the runtime equivalent of setting the 'editable' config option at config time.
54307 * @param {Boolean} value True to allow the user to directly edit the field text
54309 setEditable : function(value){
54314 onBeforeLoad : function(){
54316 Roo.log("Select before load");
54319 this.innerList.update(this.loadingText ?
54320 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
54321 //this.restrictHeight();
54322 this.selectedIndex = -1;
54326 onLoad : function(){
54329 var dom = this.el.dom;
54330 dom.innerHTML = '';
54331 var od = dom.ownerDocument;
54333 if (this.emptyText) {
54334 var op = od.createElement('option');
54335 op.setAttribute('value', '');
54336 op.innerHTML = String.format('{0}', this.emptyText);
54337 dom.appendChild(op);
54339 if(this.store.getCount() > 0){
54341 var vf = this.valueField;
54342 var df = this.displayField;
54343 this.store.data.each(function(r) {
54344 // which colmsn to use... testing - cdoe / title..
54345 var op = od.createElement('option');
54346 op.setAttribute('value', r.data[vf]);
54347 op.innerHTML = String.format('{0}', r.data[df]);
54348 dom.appendChild(op);
54350 if (typeof(this.defaultValue != 'undefined')) {
54351 this.setValue(this.defaultValue);
54356 //this.onEmptyResults();
54361 onLoadException : function()
54363 dom.innerHTML = '';
54365 Roo.log("Select on load exception");
54369 Roo.log(this.store.reader.jsonData);
54370 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
54371 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
54377 onTypeAhead : function(){
54382 onSelect : function(record, index){
54383 Roo.log('on select?');
54385 if(this.fireEvent('beforeselect', this, record, index) !== false){
54386 this.setFromData(index > -1 ? record.data : false);
54388 this.fireEvent('select', this, record, index);
54393 * Returns the currently selected field value or empty string if no value is set.
54394 * @return {String} value The selected value
54396 getValue : function(){
54397 var dom = this.el.dom;
54398 this.value = dom.options[dom.selectedIndex].value;
54404 * Clears any text/value currently set in the field
54406 clearValue : function(){
54408 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
54413 * Sets the specified value into the field. If the value finds a match, the corresponding record text
54414 * will be displayed in the field. If the value does not match the data value of an existing item,
54415 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
54416 * Otherwise the field will be blank (although the value will still be set).
54417 * @param {String} value The value to match
54419 setValue : function(v){
54420 var d = this.el.dom;
54421 for (var i =0; i < d.options.length;i++) {
54422 if (v == d.options[i].value) {
54423 d.selectedIndex = i;
54431 * @property {Object} the last set data for the element
54436 * Sets the value of the field based on a object which is related to the record format for the store.
54437 * @param {Object} value the value to set as. or false on reset?
54439 setFromData : function(o){
54440 Roo.log('setfrom data?');
54446 reset : function(){
54450 findRecord : function(prop, value){
54455 if(this.store.getCount() > 0){
54456 this.store.each(function(r){
54457 if(r.data[prop] == value){
54467 getName: function()
54469 // returns hidden if it's set..
54470 if (!this.rendered) {return ''};
54471 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
54479 onEmptyResults : function(){
54480 Roo.log('empty results');
54485 * Returns true if the dropdown list is expanded, else false.
54487 isExpanded : function(){
54492 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
54493 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
54494 * @param {String} value The data value of the item to select
54495 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
54496 * selected item if it is not currently in view (defaults to true)
54497 * @return {Boolean} True if the value matched an item in the list, else false
54499 selectByValue : function(v, scrollIntoView){
54500 Roo.log('select By Value');
54503 if(v !== undefined && v !== null){
54504 var r = this.findRecord(this.valueField || this.displayField, v);
54506 this.select(this.store.indexOf(r), scrollIntoView);
54514 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
54515 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
54516 * @param {Number} index The zero-based index of the list item to select
54517 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
54518 * selected item if it is not currently in view (defaults to true)
54520 select : function(index, scrollIntoView){
54521 Roo.log('select ');
54524 this.selectedIndex = index;
54525 this.view.select(index);
54526 if(scrollIntoView !== false){
54527 var el = this.view.getNode(index);
54529 this.innerList.scrollChildIntoView(el, false);
54537 validateBlur : function(){
54544 initQuery : function(){
54545 this.doQuery(this.getRawValue());
54549 doForce : function(){
54550 if(this.el.dom.value.length > 0){
54551 this.el.dom.value =
54552 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
54558 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
54559 * query allowing the query action to be canceled if needed.
54560 * @param {String} query The SQL query to execute
54561 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
54562 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
54563 * saved in the current store (defaults to false)
54565 doQuery : function(q, forceAll){
54567 Roo.log('doQuery?');
54568 if(q === undefined || q === null){
54573 forceAll: forceAll,
54577 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
54581 forceAll = qe.forceAll;
54582 if(forceAll === true || (q.length >= this.minChars)){
54583 if(this.lastQuery != q || this.alwaysQuery){
54584 this.lastQuery = q;
54585 if(this.mode == 'local'){
54586 this.selectedIndex = -1;
54588 this.store.clearFilter();
54590 this.store.filter(this.displayField, q);
54594 this.store.baseParams[this.queryParam] = q;
54596 params: this.getParams(q)
54601 this.selectedIndex = -1;
54608 getParams : function(q){
54610 //p[this.queryParam] = q;
54613 p.limit = this.pageSize;
54619 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
54621 collapse : function(){
54626 collapseIf : function(e){
54631 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
54633 expand : function(){
54641 * @cfg {Boolean} grow
54645 * @cfg {Number} growMin
54649 * @cfg {Number} growMax
54657 setWidth : function()
54661 getResizeEl : function(){
54664 });//<script type="text/javasscript">
54668 * @class Roo.DDView
54669 * A DnD enabled version of Roo.View.
54670 * @param {Element/String} container The Element in which to create the View.
54671 * @param {String} tpl The template string used to create the markup for each element of the View
54672 * @param {Object} config The configuration properties. These include all the config options of
54673 * {@link Roo.View} plus some specific to this class.<br>
54675 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
54676 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
54678 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
54679 .x-view-drag-insert-above {
54680 border-top:1px dotted #3366cc;
54682 .x-view-drag-insert-below {
54683 border-bottom:1px dotted #3366cc;
54689 Roo.DDView = function(container, tpl, config) {
54690 Roo.DDView.superclass.constructor.apply(this, arguments);
54691 this.getEl().setStyle("outline", "0px none");
54692 this.getEl().unselectable();
54693 if (this.dragGroup) {
54694 this.setDraggable(this.dragGroup.split(","));
54696 if (this.dropGroup) {
54697 this.setDroppable(this.dropGroup.split(","));
54699 if (this.deletable) {
54700 this.setDeletable();
54702 this.isDirtyFlag = false;
54708 Roo.extend(Roo.DDView, Roo.View, {
54709 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
54710 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
54711 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
54712 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
54716 reset: Roo.emptyFn,
54718 clearInvalid: Roo.form.Field.prototype.clearInvalid,
54720 validate: function() {
54724 destroy: function() {
54725 this.purgeListeners();
54726 this.getEl.removeAllListeners();
54727 this.getEl().remove();
54728 if (this.dragZone) {
54729 if (this.dragZone.destroy) {
54730 this.dragZone.destroy();
54733 if (this.dropZone) {
54734 if (this.dropZone.destroy) {
54735 this.dropZone.destroy();
54740 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
54741 getName: function() {
54745 /** Loads the View from a JSON string representing the Records to put into the Store. */
54746 setValue: function(v) {
54748 throw "DDView.setValue(). DDView must be constructed with a valid Store";
54751 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
54752 this.store.proxy = new Roo.data.MemoryProxy(data);
54756 /** @return {String} a parenthesised list of the ids of the Records in the View. */
54757 getValue: function() {
54759 this.store.each(function(rec) {
54760 result += rec.id + ',';
54762 return result.substr(0, result.length - 1) + ')';
54765 getIds: function() {
54766 var i = 0, result = new Array(this.store.getCount());
54767 this.store.each(function(rec) {
54768 result[i++] = rec.id;
54773 isDirty: function() {
54774 return this.isDirtyFlag;
54778 * Part of the Roo.dd.DropZone interface. If no target node is found, the
54779 * whole Element becomes the target, and this causes the drop gesture to append.
54781 getTargetFromEvent : function(e) {
54782 var target = e.getTarget();
54783 while ((target !== null) && (target.parentNode != this.el.dom)) {
54784 target = target.parentNode;
54787 target = this.el.dom.lastChild || this.el.dom;
54793 * Create the drag data which consists of an object which has the property "ddel" as
54794 * the drag proxy element.
54796 getDragData : function(e) {
54797 var target = this.findItemFromChild(e.getTarget());
54799 this.handleSelection(e);
54800 var selNodes = this.getSelectedNodes();
54803 copy: this.copy || (this.allowCopy && e.ctrlKey),
54807 var selectedIndices = this.getSelectedIndexes();
54808 for (var i = 0; i < selectedIndices.length; i++) {
54809 dragData.records.push(this.store.getAt(selectedIndices[i]));
54811 if (selNodes.length == 1) {
54812 dragData.ddel = target.cloneNode(true); // the div element
54814 var div = document.createElement('div'); // create the multi element drag "ghost"
54815 div.className = 'multi-proxy';
54816 for (var i = 0, len = selNodes.length; i < len; i++) {
54817 div.appendChild(selNodes[i].cloneNode(true));
54819 dragData.ddel = div;
54821 //console.log(dragData)
54822 //console.log(dragData.ddel.innerHTML)
54825 //console.log('nodragData')
54829 /** Specify to which ddGroup items in this DDView may be dragged. */
54830 setDraggable: function(ddGroup) {
54831 if (ddGroup instanceof Array) {
54832 Roo.each(ddGroup, this.setDraggable, this);
54835 if (this.dragZone) {
54836 this.dragZone.addToGroup(ddGroup);
54838 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
54839 containerScroll: true,
54843 // Draggability implies selection. DragZone's mousedown selects the element.
54844 if (!this.multiSelect) { this.singleSelect = true; }
54846 // Wire the DragZone's handlers up to methods in *this*
54847 this.dragZone.getDragData = this.getDragData.createDelegate(this);
54851 /** Specify from which ddGroup this DDView accepts drops. */
54852 setDroppable: function(ddGroup) {
54853 if (ddGroup instanceof Array) {
54854 Roo.each(ddGroup, this.setDroppable, this);
54857 if (this.dropZone) {
54858 this.dropZone.addToGroup(ddGroup);
54860 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
54861 containerScroll: true,
54865 // Wire the DropZone's handlers up to methods in *this*
54866 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
54867 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
54868 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
54869 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
54870 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
54874 /** Decide whether to drop above or below a View node. */
54875 getDropPoint : function(e, n, dd){
54876 if (n == this.el.dom) { return "above"; }
54877 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
54878 var c = t + (b - t) / 2;
54879 var y = Roo.lib.Event.getPageY(e);
54887 onNodeEnter : function(n, dd, e, data){
54891 onNodeOver : function(n, dd, e, data){
54892 var pt = this.getDropPoint(e, n, dd);
54893 // set the insert point style on the target node
54894 var dragElClass = this.dropNotAllowed;
54897 if (pt == "above"){
54898 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
54899 targetElClass = "x-view-drag-insert-above";
54901 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
54902 targetElClass = "x-view-drag-insert-below";
54904 if (this.lastInsertClass != targetElClass){
54905 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
54906 this.lastInsertClass = targetElClass;
54909 return dragElClass;
54912 onNodeOut : function(n, dd, e, data){
54913 this.removeDropIndicators(n);
54916 onNodeDrop : function(n, dd, e, data){
54917 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
54920 var pt = this.getDropPoint(e, n, dd);
54921 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
54922 if (pt == "below") { insertAt++; }
54923 for (var i = 0; i < data.records.length; i++) {
54924 var r = data.records[i];
54925 var dup = this.store.getById(r.id);
54926 if (dup && (dd != this.dragZone)) {
54927 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
54930 this.store.insert(insertAt++, r.copy());
54932 data.source.isDirtyFlag = true;
54934 this.store.insert(insertAt++, r);
54936 this.isDirtyFlag = true;
54939 this.dragZone.cachedTarget = null;
54943 removeDropIndicators : function(n){
54945 Roo.fly(n).removeClass([
54946 "x-view-drag-insert-above",
54947 "x-view-drag-insert-below"]);
54948 this.lastInsertClass = "_noclass";
54953 * Utility method. Add a delete option to the DDView's context menu.
54954 * @param {String} imageUrl The URL of the "delete" icon image.
54956 setDeletable: function(imageUrl) {
54957 if (!this.singleSelect && !this.multiSelect) {
54958 this.singleSelect = true;
54960 var c = this.getContextMenu();
54961 this.contextMenu.on("itemclick", function(item) {
54964 this.remove(this.getSelectedIndexes());
54968 this.contextMenu.add({
54975 /** Return the context menu for this DDView. */
54976 getContextMenu: function() {
54977 if (!this.contextMenu) {
54978 // Create the View's context menu
54979 this.contextMenu = new Roo.menu.Menu({
54980 id: this.id + "-contextmenu"
54982 this.el.on("contextmenu", this.showContextMenu, this);
54984 return this.contextMenu;
54987 disableContextMenu: function() {
54988 if (this.contextMenu) {
54989 this.el.un("contextmenu", this.showContextMenu, this);
54993 showContextMenu: function(e, item) {
54994 item = this.findItemFromChild(e.getTarget());
54997 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
54998 this.contextMenu.showAt(e.getXY());
55003 * Remove {@link Roo.data.Record}s at the specified indices.
55004 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
55006 remove: function(selectedIndices) {
55007 selectedIndices = [].concat(selectedIndices);
55008 for (var i = 0; i < selectedIndices.length; i++) {
55009 var rec = this.store.getAt(selectedIndices[i]);
55010 this.store.remove(rec);
55015 * Double click fires the event, but also, if this is draggable, and there is only one other
55016 * related DropZone, it transfers the selected node.
55018 onDblClick : function(e){
55019 var item = this.findItemFromChild(e.getTarget());
55021 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
55024 if (this.dragGroup) {
55025 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
55026 while (targets.indexOf(this.dropZone) > -1) {
55027 targets.remove(this.dropZone);
55029 if (targets.length == 1) {
55030 this.dragZone.cachedTarget = null;
55031 var el = Roo.get(targets[0].getEl());
55032 var box = el.getBox(true);
55033 targets[0].onNodeDrop(el.dom, {
55035 xy: [box.x, box.y + box.height - 1]
55036 }, null, this.getDragData(e));
55042 handleSelection: function(e) {
55043 this.dragZone.cachedTarget = null;
55044 var item = this.findItemFromChild(e.getTarget());
55046 this.clearSelections(true);
55049 if (item && (this.multiSelect || this.singleSelect)){
55050 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
55051 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
55052 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
55053 this.unselect(item);
55055 this.select(item, this.multiSelect && e.ctrlKey);
55056 this.lastSelection = item;
55061 onItemClick : function(item, index, e){
55062 if(this.fireEvent("beforeclick", this, index, item, e) === false){
55068 unselect : function(nodeInfo, suppressEvent){
55069 var node = this.getNode(nodeInfo);
55070 if(node && this.isSelected(node)){
55071 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
55072 Roo.fly(node).removeClass(this.selectedClass);
55073 this.selections.remove(node);
55074 if(!suppressEvent){
55075 this.fireEvent("selectionchange", this, this.selections);
55083 * Ext JS Library 1.1.1
55084 * Copyright(c) 2006-2007, Ext JS, LLC.
55086 * Originally Released Under LGPL - original licence link has changed is not relivant.
55089 * <script type="text/javascript">
55093 * @class Roo.LayoutManager
55094 * @extends Roo.util.Observable
55095 * Base class for layout managers.
55097 Roo.LayoutManager = function(container, config){
55098 Roo.LayoutManager.superclass.constructor.call(this);
55099 this.el = Roo.get(container);
55100 // ie scrollbar fix
55101 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
55102 document.body.scroll = "no";
55103 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
55104 this.el.position('relative');
55106 this.id = this.el.id;
55107 this.el.addClass("x-layout-container");
55108 /** false to disable window resize monitoring @type Boolean */
55109 this.monitorWindowResize = true;
55114 * Fires when a layout is performed.
55115 * @param {Roo.LayoutManager} this
55119 * @event regionresized
55120 * Fires when the user resizes a region.
55121 * @param {Roo.LayoutRegion} region The resized region
55122 * @param {Number} newSize The new size (width for east/west, height for north/south)
55124 "regionresized" : true,
55126 * @event regioncollapsed
55127 * Fires when a region is collapsed.
55128 * @param {Roo.LayoutRegion} region The collapsed region
55130 "regioncollapsed" : true,
55132 * @event regionexpanded
55133 * Fires when a region is expanded.
55134 * @param {Roo.LayoutRegion} region The expanded region
55136 "regionexpanded" : true
55138 this.updating = false;
55139 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
55142 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
55144 * Returns true if this layout is currently being updated
55145 * @return {Boolean}
55147 isUpdating : function(){
55148 return this.updating;
55152 * Suspend the LayoutManager from doing auto-layouts while
55153 * making multiple add or remove calls
55155 beginUpdate : function(){
55156 this.updating = true;
55160 * Restore auto-layouts and optionally disable the manager from performing a layout
55161 * @param {Boolean} noLayout true to disable a layout update
55163 endUpdate : function(noLayout){
55164 this.updating = false;
55170 layout: function(){
55174 onRegionResized : function(region, newSize){
55175 this.fireEvent("regionresized", region, newSize);
55179 onRegionCollapsed : function(region){
55180 this.fireEvent("regioncollapsed", region);
55183 onRegionExpanded : function(region){
55184 this.fireEvent("regionexpanded", region);
55188 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
55189 * performs box-model adjustments.
55190 * @return {Object} The size as an object {width: (the width), height: (the height)}
55192 getViewSize : function(){
55194 if(this.el.dom != document.body){
55195 size = this.el.getSize();
55197 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
55199 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
55200 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
55205 * Returns the Element this layout is bound to.
55206 * @return {Roo.Element}
55208 getEl : function(){
55213 * Returns the specified region.
55214 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
55215 * @return {Roo.LayoutRegion}
55217 getRegion : function(target){
55218 return this.regions[target.toLowerCase()];
55221 onWindowResize : function(){
55222 if(this.monitorWindowResize){
55228 * Ext JS Library 1.1.1
55229 * Copyright(c) 2006-2007, Ext JS, LLC.
55231 * Originally Released Under LGPL - original licence link has changed is not relivant.
55234 * <script type="text/javascript">
55237 * @class Roo.BorderLayout
55238 * @extends Roo.LayoutManager
55239 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
55240 * please see: <br><br>
55241 * <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>
55242 * <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>
55245 var layout = new Roo.BorderLayout(document.body, {
55279 preferredTabWidth: 150
55284 var CP = Roo.ContentPanel;
55286 layout.beginUpdate();
55287 layout.add("north", new CP("north", "North"));
55288 layout.add("south", new CP("south", {title: "South", closable: true}));
55289 layout.add("west", new CP("west", {title: "West"}));
55290 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
55291 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
55292 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
55293 layout.getRegion("center").showPanel("center1");
55294 layout.endUpdate();
55297 <b>The container the layout is rendered into can be either the body element or any other element.
55298 If it is not the body element, the container needs to either be an absolute positioned element,
55299 or you will need to add "position:relative" to the css of the container. You will also need to specify
55300 the container size if it is not the body element.</b>
55303 * Create a new BorderLayout
55304 * @param {String/HTMLElement/Element} container The container this layout is bound to
55305 * @param {Object} config Configuration options
55307 Roo.BorderLayout = function(container, config){
55308 config = config || {};
55309 Roo.BorderLayout.superclass.constructor.call(this, container, config);
55310 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
55311 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
55312 var target = this.factory.validRegions[i];
55313 if(config[target]){
55314 this.addRegion(target, config[target]);
55319 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
55321 * Creates and adds a new region if it doesn't already exist.
55322 * @param {String} target The target region key (north, south, east, west or center).
55323 * @param {Object} config The regions config object
55324 * @return {BorderLayoutRegion} The new region
55326 addRegion : function(target, config){
55327 if(!this.regions[target]){
55328 var r = this.factory.create(target, this, config);
55329 this.bindRegion(target, r);
55331 return this.regions[target];
55335 bindRegion : function(name, r){
55336 this.regions[name] = r;
55337 r.on("visibilitychange", this.layout, this);
55338 r.on("paneladded", this.layout, this);
55339 r.on("panelremoved", this.layout, this);
55340 r.on("invalidated", this.layout, this);
55341 r.on("resized", this.onRegionResized, this);
55342 r.on("collapsed", this.onRegionCollapsed, this);
55343 r.on("expanded", this.onRegionExpanded, this);
55347 * Performs a layout update.
55349 layout : function(){
55350 if(this.updating) {
55353 var size = this.getViewSize();
55354 var w = size.width;
55355 var h = size.height;
55360 //var x = 0, y = 0;
55362 var rs = this.regions;
55363 var north = rs["north"];
55364 var south = rs["south"];
55365 var west = rs["west"];
55366 var east = rs["east"];
55367 var center = rs["center"];
55368 //if(this.hideOnLayout){ // not supported anymore
55369 //c.el.setStyle("display", "none");
55371 if(north && north.isVisible()){
55372 var b = north.getBox();
55373 var m = north.getMargins();
55374 b.width = w - (m.left+m.right);
55377 centerY = b.height + b.y + m.bottom;
55378 centerH -= centerY;
55379 north.updateBox(this.safeBox(b));
55381 if(south && south.isVisible()){
55382 var b = south.getBox();
55383 var m = south.getMargins();
55384 b.width = w - (m.left+m.right);
55386 var totalHeight = (b.height + m.top + m.bottom);
55387 b.y = h - totalHeight + m.top;
55388 centerH -= totalHeight;
55389 south.updateBox(this.safeBox(b));
55391 if(west && west.isVisible()){
55392 var b = west.getBox();
55393 var m = west.getMargins();
55394 b.height = centerH - (m.top+m.bottom);
55396 b.y = centerY + m.top;
55397 var totalWidth = (b.width + m.left + m.right);
55398 centerX += totalWidth;
55399 centerW -= totalWidth;
55400 west.updateBox(this.safeBox(b));
55402 if(east && east.isVisible()){
55403 var b = east.getBox();
55404 var m = east.getMargins();
55405 b.height = centerH - (m.top+m.bottom);
55406 var totalWidth = (b.width + m.left + m.right);
55407 b.x = w - totalWidth + m.left;
55408 b.y = centerY + m.top;
55409 centerW -= totalWidth;
55410 east.updateBox(this.safeBox(b));
55413 var m = center.getMargins();
55415 x: centerX + m.left,
55416 y: centerY + m.top,
55417 width: centerW - (m.left+m.right),
55418 height: centerH - (m.top+m.bottom)
55420 //if(this.hideOnLayout){
55421 //center.el.setStyle("display", "block");
55423 center.updateBox(this.safeBox(centerBox));
55426 this.fireEvent("layout", this);
55430 safeBox : function(box){
55431 box.width = Math.max(0, box.width);
55432 box.height = Math.max(0, box.height);
55437 * Adds a ContentPanel (or subclass) to this layout.
55438 * @param {String} target The target region key (north, south, east, west or center).
55439 * @param {Roo.ContentPanel} panel The panel to add
55440 * @return {Roo.ContentPanel} The added panel
55442 add : function(target, panel){
55444 target = target.toLowerCase();
55445 return this.regions[target].add(panel);
55449 * Remove a ContentPanel (or subclass) to this layout.
55450 * @param {String} target The target region key (north, south, east, west or center).
55451 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
55452 * @return {Roo.ContentPanel} The removed panel
55454 remove : function(target, panel){
55455 target = target.toLowerCase();
55456 return this.regions[target].remove(panel);
55460 * Searches all regions for a panel with the specified id
55461 * @param {String} panelId
55462 * @return {Roo.ContentPanel} The panel or null if it wasn't found
55464 findPanel : function(panelId){
55465 var rs = this.regions;
55466 for(var target in rs){
55467 if(typeof rs[target] != "function"){
55468 var p = rs[target].getPanel(panelId);
55478 * Searches all regions for a panel with the specified id and activates (shows) it.
55479 * @param {String/ContentPanel} panelId The panels id or the panel itself
55480 * @return {Roo.ContentPanel} The shown panel or null
55482 showPanel : function(panelId) {
55483 var rs = this.regions;
55484 for(var target in rs){
55485 var r = rs[target];
55486 if(typeof r != "function"){
55487 if(r.hasPanel(panelId)){
55488 return r.showPanel(panelId);
55496 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
55497 * @param {Roo.state.Provider} provider (optional) An alternate state provider
55499 restoreState : function(provider){
55501 provider = Roo.state.Manager;
55503 var sm = new Roo.LayoutStateManager();
55504 sm.init(this, provider);
55508 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
55509 * object should contain properties for each region to add ContentPanels to, and each property's value should be
55510 * a valid ContentPanel config object. Example:
55512 // Create the main layout
55513 var layout = new Roo.BorderLayout('main-ct', {
55524 // Create and add multiple ContentPanels at once via configs
55527 id: 'source-files',
55529 title:'Ext Source Files',
55542 * @param {Object} regions An object containing ContentPanel configs by region name
55544 batchAdd : function(regions){
55545 this.beginUpdate();
55546 for(var rname in regions){
55547 var lr = this.regions[rname];
55549 this.addTypedPanels(lr, regions[rname]);
55556 addTypedPanels : function(lr, ps){
55557 if(typeof ps == 'string'){
55558 lr.add(new Roo.ContentPanel(ps));
55560 else if(ps instanceof Array){
55561 for(var i =0, len = ps.length; i < len; i++){
55562 this.addTypedPanels(lr, ps[i]);
55565 else if(!ps.events){ // raw config?
55567 delete ps.el; // prevent conflict
55568 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
55570 else { // panel object assumed!
55575 * Adds a xtype elements to the layout.
55579 xtype : 'ContentPanel',
55586 xtype : 'NestedLayoutPanel',
55592 items : [ ... list of content panels or nested layout panels.. ]
55596 * @param {Object} cfg Xtype definition of item to add.
55598 addxtype : function(cfg)
55600 // basically accepts a pannel...
55601 // can accept a layout region..!?!?
55602 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
55604 if (!cfg.xtype.match(/Panel$/)) {
55609 if (typeof(cfg.region) == 'undefined') {
55610 Roo.log("Failed to add Panel, region was not set");
55614 var region = cfg.region;
55620 xitems = cfg.items;
55627 case 'ContentPanel': // ContentPanel (el, cfg)
55628 case 'ScrollPanel': // ContentPanel (el, cfg)
55630 if(cfg.autoCreate) {
55631 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
55633 var el = this.el.createChild();
55634 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
55637 this.add(region, ret);
55641 case 'TreePanel': // our new panel!
55642 cfg.el = this.el.createChild();
55643 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
55644 this.add(region, ret);
55647 case 'NestedLayoutPanel':
55648 // create a new Layout (which is a Border Layout...
55649 var el = this.el.createChild();
55650 var clayout = cfg.layout;
55652 clayout.items = clayout.items || [];
55653 // replace this exitems with the clayout ones..
55654 xitems = clayout.items;
55657 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
55658 cfg.background = false;
55660 var layout = new Roo.BorderLayout(el, clayout);
55662 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
55663 //console.log('adding nested layout panel ' + cfg.toSource());
55664 this.add(region, ret);
55665 nb = {}; /// find first...
55670 // needs grid and region
55672 //var el = this.getRegion(region).el.createChild();
55673 var el = this.el.createChild();
55674 // create the grid first...
55676 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
55678 if (region == 'center' && this.active ) {
55679 cfg.background = false;
55681 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
55683 this.add(region, ret);
55684 if (cfg.background) {
55685 ret.on('activate', function(gp) {
55686 if (!gp.grid.rendered) {
55701 if (typeof(Roo[cfg.xtype]) != 'undefined') {
55703 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
55704 this.add(region, ret);
55707 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
55711 // GridPanel (grid, cfg)
55714 this.beginUpdate();
55718 Roo.each(xitems, function(i) {
55719 region = nb && i.region ? i.region : false;
55721 var add = ret.addxtype(i);
55724 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
55725 if (!i.background) {
55726 abn[region] = nb[region] ;
55733 // make the last non-background panel active..
55734 //if (nb) { Roo.log(abn); }
55737 for(var r in abn) {
55738 region = this.getRegion(r);
55740 // tried using nb[r], but it does not work..
55742 region.showPanel(abn[r]);
55753 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
55754 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
55755 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
55756 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
55759 var CP = Roo.ContentPanel;
55761 var layout = Roo.BorderLayout.create({
55765 panels: [new CP("north", "North")]
55774 panels: [new CP("west", {title: "West"})]
55783 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
55792 panels: [new CP("south", {title: "South", closable: true})]
55799 preferredTabWidth: 150,
55801 new CP("center1", {title: "Close Me", closable: true}),
55802 new CP("center2", {title: "Center Panel", closable: false})
55807 layout.getRegion("center").showPanel("center1");
55812 Roo.BorderLayout.create = function(config, targetEl){
55813 var layout = new Roo.BorderLayout(targetEl || document.body, config);
55814 layout.beginUpdate();
55815 var regions = Roo.BorderLayout.RegionFactory.validRegions;
55816 for(var j = 0, jlen = regions.length; j < jlen; j++){
55817 var lr = regions[j];
55818 if(layout.regions[lr] && config[lr].panels){
55819 var r = layout.regions[lr];
55820 var ps = config[lr].panels;
55821 layout.addTypedPanels(r, ps);
55824 layout.endUpdate();
55829 Roo.BorderLayout.RegionFactory = {
55831 validRegions : ["north","south","east","west","center"],
55834 create : function(target, mgr, config){
55835 target = target.toLowerCase();
55836 if(config.lightweight || config.basic){
55837 return new Roo.BasicLayoutRegion(mgr, config, target);
55841 return new Roo.NorthLayoutRegion(mgr, config);
55843 return new Roo.SouthLayoutRegion(mgr, config);
55845 return new Roo.EastLayoutRegion(mgr, config);
55847 return new Roo.WestLayoutRegion(mgr, config);
55849 return new Roo.CenterLayoutRegion(mgr, config);
55851 throw 'Layout region "'+target+'" not supported.';
55855 * Ext JS Library 1.1.1
55856 * Copyright(c) 2006-2007, Ext JS, LLC.
55858 * Originally Released Under LGPL - original licence link has changed is not relivant.
55861 * <script type="text/javascript">
55865 * @class Roo.BasicLayoutRegion
55866 * @extends Roo.util.Observable
55867 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
55868 * and does not have a titlebar, tabs or any other features. All it does is size and position
55869 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
55871 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
55873 this.position = pos;
55876 * @scope Roo.BasicLayoutRegion
55880 * @event beforeremove
55881 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
55882 * @param {Roo.LayoutRegion} this
55883 * @param {Roo.ContentPanel} panel The panel
55884 * @param {Object} e The cancel event object
55886 "beforeremove" : true,
55888 * @event invalidated
55889 * Fires when the layout for this region is changed.
55890 * @param {Roo.LayoutRegion} this
55892 "invalidated" : true,
55894 * @event visibilitychange
55895 * Fires when this region is shown or hidden
55896 * @param {Roo.LayoutRegion} this
55897 * @param {Boolean} visibility true or false
55899 "visibilitychange" : true,
55901 * @event paneladded
55902 * Fires when a panel is added.
55903 * @param {Roo.LayoutRegion} this
55904 * @param {Roo.ContentPanel} panel The panel
55906 "paneladded" : true,
55908 * @event panelremoved
55909 * Fires when a panel is removed.
55910 * @param {Roo.LayoutRegion} this
55911 * @param {Roo.ContentPanel} panel The panel
55913 "panelremoved" : true,
55915 * @event beforecollapse
55916 * Fires when this region before collapse.
55917 * @param {Roo.LayoutRegion} this
55919 "beforecollapse" : true,
55922 * Fires when this region is collapsed.
55923 * @param {Roo.LayoutRegion} this
55925 "collapsed" : true,
55928 * Fires when this region is expanded.
55929 * @param {Roo.LayoutRegion} this
55934 * Fires when this region is slid into view.
55935 * @param {Roo.LayoutRegion} this
55937 "slideshow" : true,
55940 * Fires when this region slides out of view.
55941 * @param {Roo.LayoutRegion} this
55943 "slidehide" : true,
55945 * @event panelactivated
55946 * Fires when a panel is activated.
55947 * @param {Roo.LayoutRegion} this
55948 * @param {Roo.ContentPanel} panel The activated panel
55950 "panelactivated" : true,
55953 * Fires when the user resizes this region.
55954 * @param {Roo.LayoutRegion} this
55955 * @param {Number} newSize The new size (width for east/west, height for north/south)
55959 /** A collection of panels in this region. @type Roo.util.MixedCollection */
55960 this.panels = new Roo.util.MixedCollection();
55961 this.panels.getKey = this.getPanelId.createDelegate(this);
55963 this.activePanel = null;
55964 // ensure listeners are added...
55966 if (config.listeners || config.events) {
55967 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
55968 listeners : config.listeners || {},
55969 events : config.events || {}
55973 if(skipConfig !== true){
55974 this.applyConfig(config);
55978 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
55979 getPanelId : function(p){
55983 applyConfig : function(config){
55984 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
55985 this.config = config;
55990 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
55991 * the width, for horizontal (north, south) the height.
55992 * @param {Number} newSize The new width or height
55994 resizeTo : function(newSize){
55995 var el = this.el ? this.el :
55996 (this.activePanel ? this.activePanel.getEl() : null);
55998 switch(this.position){
56001 el.setWidth(newSize);
56002 this.fireEvent("resized", this, newSize);
56006 el.setHeight(newSize);
56007 this.fireEvent("resized", this, newSize);
56013 getBox : function(){
56014 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
56017 getMargins : function(){
56018 return this.margins;
56021 updateBox : function(box){
56023 var el = this.activePanel.getEl();
56024 el.dom.style.left = box.x + "px";
56025 el.dom.style.top = box.y + "px";
56026 this.activePanel.setSize(box.width, box.height);
56030 * Returns the container element for this region.
56031 * @return {Roo.Element}
56033 getEl : function(){
56034 return this.activePanel;
56038 * Returns true if this region is currently visible.
56039 * @return {Boolean}
56041 isVisible : function(){
56042 return this.activePanel ? true : false;
56045 setActivePanel : function(panel){
56046 panel = this.getPanel(panel);
56047 if(this.activePanel && this.activePanel != panel){
56048 this.activePanel.setActiveState(false);
56049 this.activePanel.getEl().setLeftTop(-10000,-10000);
56051 this.activePanel = panel;
56052 panel.setActiveState(true);
56054 panel.setSize(this.box.width, this.box.height);
56056 this.fireEvent("panelactivated", this, panel);
56057 this.fireEvent("invalidated");
56061 * Show the specified panel.
56062 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
56063 * @return {Roo.ContentPanel} The shown panel or null
56065 showPanel : function(panel){
56066 if(panel = this.getPanel(panel)){
56067 this.setActivePanel(panel);
56073 * Get the active panel for this region.
56074 * @return {Roo.ContentPanel} The active panel or null
56076 getActivePanel : function(){
56077 return this.activePanel;
56081 * Add the passed ContentPanel(s)
56082 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
56083 * @return {Roo.ContentPanel} The panel added (if only one was added)
56085 add : function(panel){
56086 if(arguments.length > 1){
56087 for(var i = 0, len = arguments.length; i < len; i++) {
56088 this.add(arguments[i]);
56092 if(this.hasPanel(panel)){
56093 this.showPanel(panel);
56096 var el = panel.getEl();
56097 if(el.dom.parentNode != this.mgr.el.dom){
56098 this.mgr.el.dom.appendChild(el.dom);
56100 if(panel.setRegion){
56101 panel.setRegion(this);
56103 this.panels.add(panel);
56104 el.setStyle("position", "absolute");
56105 if(!panel.background){
56106 this.setActivePanel(panel);
56107 if(this.config.initialSize && this.panels.getCount()==1){
56108 this.resizeTo(this.config.initialSize);
56111 this.fireEvent("paneladded", this, panel);
56116 * Returns true if the panel is in this region.
56117 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
56118 * @return {Boolean}
56120 hasPanel : function(panel){
56121 if(typeof panel == "object"){ // must be panel obj
56122 panel = panel.getId();
56124 return this.getPanel(panel) ? true : false;
56128 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
56129 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
56130 * @param {Boolean} preservePanel Overrides the config preservePanel option
56131 * @return {Roo.ContentPanel} The panel that was removed
56133 remove : function(panel, preservePanel){
56134 panel = this.getPanel(panel);
56139 this.fireEvent("beforeremove", this, panel, e);
56140 if(e.cancel === true){
56143 var panelId = panel.getId();
56144 this.panels.removeKey(panelId);
56149 * Returns the panel specified or null if it's not in this region.
56150 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
56151 * @return {Roo.ContentPanel}
56153 getPanel : function(id){
56154 if(typeof id == "object"){ // must be panel obj
56157 return this.panels.get(id);
56161 * Returns this regions position (north/south/east/west/center).
56164 getPosition: function(){
56165 return this.position;
56169 * Ext JS Library 1.1.1
56170 * Copyright(c) 2006-2007, Ext JS, LLC.
56172 * Originally Released Under LGPL - original licence link has changed is not relivant.
56175 * <script type="text/javascript">
56179 * @class Roo.LayoutRegion
56180 * @extends Roo.BasicLayoutRegion
56181 * This class represents a region in a layout manager.
56182 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
56183 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
56184 * @cfg {Boolean} floatable False to disable floating (defaults to true)
56185 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
56186 * @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})
56187 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
56188 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
56189 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
56190 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
56191 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
56192 * @cfg {String} title The title for the region (overrides panel titles)
56193 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
56194 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
56195 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
56196 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
56197 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
56198 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
56199 * the space available, similar to FireFox 1.5 tabs (defaults to false)
56200 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
56201 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
56202 * @cfg {Boolean} showPin True to show a pin button
56203 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
56204 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
56205 * @cfg {Boolean} disableTabTips True to disable tab tooltips
56206 * @cfg {Number} width For East/West panels
56207 * @cfg {Number} height For North/South panels
56208 * @cfg {Boolean} split To show the splitter
56209 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
56211 Roo.LayoutRegion = function(mgr, config, pos){
56212 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
56213 var dh = Roo.DomHelper;
56214 /** This region's container element
56215 * @type Roo.Element */
56216 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
56217 /** This region's title element
56218 * @type Roo.Element */
56220 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
56221 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
56222 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
56224 this.titleEl.enableDisplayMode();
56225 /** This region's title text element
56226 * @type HTMLElement */
56227 this.titleTextEl = this.titleEl.dom.firstChild;
56228 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
56229 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
56230 this.closeBtn.enableDisplayMode();
56231 this.closeBtn.on("click", this.closeClicked, this);
56232 this.closeBtn.hide();
56234 this.createBody(config);
56235 this.visible = true;
56236 this.collapsed = false;
56238 if(config.hideWhenEmpty){
56240 this.on("paneladded", this.validateVisibility, this);
56241 this.on("panelremoved", this.validateVisibility, this);
56243 this.applyConfig(config);
56246 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
56248 createBody : function(){
56249 /** This region's body element
56250 * @type Roo.Element */
56251 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
56254 applyConfig : function(c){
56255 if(c.collapsible && this.position != "center" && !this.collapsedEl){
56256 var dh = Roo.DomHelper;
56257 if(c.titlebar !== false){
56258 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
56259 this.collapseBtn.on("click", this.collapse, this);
56260 this.collapseBtn.enableDisplayMode();
56262 if(c.showPin === true || this.showPin){
56263 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
56264 this.stickBtn.enableDisplayMode();
56265 this.stickBtn.on("click", this.expand, this);
56266 this.stickBtn.hide();
56269 /** This region's collapsed element
56270 * @type Roo.Element */
56271 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
56272 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
56274 if(c.floatable !== false){
56275 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
56276 this.collapsedEl.on("click", this.collapseClick, this);
56279 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
56280 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
56281 id: "message", unselectable: "on", style:{"float":"left"}});
56282 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
56284 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
56285 this.expandBtn.on("click", this.expand, this);
56287 if(this.collapseBtn){
56288 this.collapseBtn.setVisible(c.collapsible == true);
56290 this.cmargins = c.cmargins || this.cmargins ||
56291 (this.position == "west" || this.position == "east" ?
56292 {top: 0, left: 2, right:2, bottom: 0} :
56293 {top: 2, left: 0, right:0, bottom: 2});
56294 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
56295 this.bottomTabs = c.tabPosition != "top";
56296 this.autoScroll = c.autoScroll || false;
56297 if(this.autoScroll){
56298 this.bodyEl.setStyle("overflow", "auto");
56300 this.bodyEl.setStyle("overflow", "hidden");
56302 //if(c.titlebar !== false){
56303 if((!c.titlebar && !c.title) || c.titlebar === false){
56304 this.titleEl.hide();
56306 this.titleEl.show();
56308 this.titleTextEl.innerHTML = c.title;
56312 this.duration = c.duration || .30;
56313 this.slideDuration = c.slideDuration || .45;
56316 this.collapse(true);
56323 * Returns true if this region is currently visible.
56324 * @return {Boolean}
56326 isVisible : function(){
56327 return this.visible;
56331 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
56332 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
56334 setCollapsedTitle : function(title){
56335 title = title || " ";
56336 if(this.collapsedTitleTextEl){
56337 this.collapsedTitleTextEl.innerHTML = title;
56341 getBox : function(){
56343 if(!this.collapsed){
56344 b = this.el.getBox(false, true);
56346 b = this.collapsedEl.getBox(false, true);
56351 getMargins : function(){
56352 return this.collapsed ? this.cmargins : this.margins;
56355 highlight : function(){
56356 this.el.addClass("x-layout-panel-dragover");
56359 unhighlight : function(){
56360 this.el.removeClass("x-layout-panel-dragover");
56363 updateBox : function(box){
56365 if(!this.collapsed){
56366 this.el.dom.style.left = box.x + "px";
56367 this.el.dom.style.top = box.y + "px";
56368 this.updateBody(box.width, box.height);
56370 this.collapsedEl.dom.style.left = box.x + "px";
56371 this.collapsedEl.dom.style.top = box.y + "px";
56372 this.collapsedEl.setSize(box.width, box.height);
56375 this.tabs.autoSizeTabs();
56379 updateBody : function(w, h){
56381 this.el.setWidth(w);
56382 w -= this.el.getBorderWidth("rl");
56383 if(this.config.adjustments){
56384 w += this.config.adjustments[0];
56388 this.el.setHeight(h);
56389 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
56390 h -= this.el.getBorderWidth("tb");
56391 if(this.config.adjustments){
56392 h += this.config.adjustments[1];
56394 this.bodyEl.setHeight(h);
56396 h = this.tabs.syncHeight(h);
56399 if(this.panelSize){
56400 w = w !== null ? w : this.panelSize.width;
56401 h = h !== null ? h : this.panelSize.height;
56403 if(this.activePanel){
56404 var el = this.activePanel.getEl();
56405 w = w !== null ? w : el.getWidth();
56406 h = h !== null ? h : el.getHeight();
56407 this.panelSize = {width: w, height: h};
56408 this.activePanel.setSize(w, h);
56410 if(Roo.isIE && this.tabs){
56411 this.tabs.el.repaint();
56416 * Returns the container element for this region.
56417 * @return {Roo.Element}
56419 getEl : function(){
56424 * Hides this region.
56427 if(!this.collapsed){
56428 this.el.dom.style.left = "-2000px";
56431 this.collapsedEl.dom.style.left = "-2000px";
56432 this.collapsedEl.hide();
56434 this.visible = false;
56435 this.fireEvent("visibilitychange", this, false);
56439 * Shows this region if it was previously hidden.
56442 if(!this.collapsed){
56445 this.collapsedEl.show();
56447 this.visible = true;
56448 this.fireEvent("visibilitychange", this, true);
56451 closeClicked : function(){
56452 if(this.activePanel){
56453 this.remove(this.activePanel);
56457 collapseClick : function(e){
56459 e.stopPropagation();
56462 e.stopPropagation();
56468 * Collapses this region.
56469 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
56471 collapse : function(skipAnim, skipCheck = false){
56472 if(this.collapsed) {
56476 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
56478 this.collapsed = true;
56480 this.split.el.hide();
56482 if(this.config.animate && skipAnim !== true){
56483 this.fireEvent("invalidated", this);
56484 this.animateCollapse();
56486 this.el.setLocation(-20000,-20000);
56488 this.collapsedEl.show();
56489 this.fireEvent("collapsed", this);
56490 this.fireEvent("invalidated", this);
56496 animateCollapse : function(){
56501 * Expands this region if it was previously collapsed.
56502 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
56503 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
56505 expand : function(e, skipAnim){
56507 e.stopPropagation();
56509 if(!this.collapsed || this.el.hasActiveFx()) {
56513 this.afterSlideIn();
56516 this.collapsed = false;
56517 if(this.config.animate && skipAnim !== true){
56518 this.animateExpand();
56522 this.split.el.show();
56524 this.collapsedEl.setLocation(-2000,-2000);
56525 this.collapsedEl.hide();
56526 this.fireEvent("invalidated", this);
56527 this.fireEvent("expanded", this);
56531 animateExpand : function(){
56535 initTabs : function()
56537 this.bodyEl.setStyle("overflow", "hidden");
56538 var ts = new Roo.TabPanel(
56541 tabPosition: this.bottomTabs ? 'bottom' : 'top',
56542 disableTooltips: this.config.disableTabTips,
56543 toolbar : this.config.toolbar
56546 if(this.config.hideTabs){
56547 ts.stripWrap.setDisplayed(false);
56550 ts.resizeTabs = this.config.resizeTabs === true;
56551 ts.minTabWidth = this.config.minTabWidth || 40;
56552 ts.maxTabWidth = this.config.maxTabWidth || 250;
56553 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
56554 ts.monitorResize = false;
56555 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
56556 ts.bodyEl.addClass('x-layout-tabs-body');
56557 this.panels.each(this.initPanelAsTab, this);
56560 initPanelAsTab : function(panel){
56561 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
56562 this.config.closeOnTab && panel.isClosable());
56563 if(panel.tabTip !== undefined){
56564 ti.setTooltip(panel.tabTip);
56566 ti.on("activate", function(){
56567 this.setActivePanel(panel);
56569 if(this.config.closeOnTab){
56570 ti.on("beforeclose", function(t, e){
56572 this.remove(panel);
56578 updatePanelTitle : function(panel, title){
56579 if(this.activePanel == panel){
56580 this.updateTitle(title);
56583 var ti = this.tabs.getTab(panel.getEl().id);
56585 if(panel.tabTip !== undefined){
56586 ti.setTooltip(panel.tabTip);
56591 updateTitle : function(title){
56592 if(this.titleTextEl && !this.config.title){
56593 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
56597 setActivePanel : function(panel){
56598 panel = this.getPanel(panel);
56599 if(this.activePanel && this.activePanel != panel){
56600 this.activePanel.setActiveState(false);
56602 this.activePanel = panel;
56603 panel.setActiveState(true);
56604 if(this.panelSize){
56605 panel.setSize(this.panelSize.width, this.panelSize.height);
56608 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
56610 this.updateTitle(panel.getTitle());
56612 this.fireEvent("invalidated", this);
56614 this.fireEvent("panelactivated", this, panel);
56618 * Shows the specified panel.
56619 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
56620 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
56622 showPanel : function(panel)
56624 panel = this.getPanel(panel);
56627 var tab = this.tabs.getTab(panel.getEl().id);
56628 if(tab.isHidden()){
56629 this.tabs.unhideTab(tab.id);
56633 this.setActivePanel(panel);
56640 * Get the active panel for this region.
56641 * @return {Roo.ContentPanel} The active panel or null
56643 getActivePanel : function(){
56644 return this.activePanel;
56647 validateVisibility : function(){
56648 if(this.panels.getCount() < 1){
56649 this.updateTitle(" ");
56650 this.closeBtn.hide();
56653 if(!this.isVisible()){
56660 * Adds the passed ContentPanel(s) to this region.
56661 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
56662 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
56664 add : function(panel){
56665 if(arguments.length > 1){
56666 for(var i = 0, len = arguments.length; i < len; i++) {
56667 this.add(arguments[i]);
56671 if(this.hasPanel(panel)){
56672 this.showPanel(panel);
56675 panel.setRegion(this);
56676 this.panels.add(panel);
56677 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
56678 this.bodyEl.dom.appendChild(panel.getEl().dom);
56679 if(panel.background !== true){
56680 this.setActivePanel(panel);
56682 this.fireEvent("paneladded", this, panel);
56688 this.initPanelAsTab(panel);
56690 if(panel.background !== true){
56691 this.tabs.activate(panel.getEl().id);
56693 this.fireEvent("paneladded", this, panel);
56698 * Hides the tab for the specified panel.
56699 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
56701 hidePanel : function(panel){
56702 if(this.tabs && (panel = this.getPanel(panel))){
56703 this.tabs.hideTab(panel.getEl().id);
56708 * Unhides the tab for a previously hidden panel.
56709 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
56711 unhidePanel : function(panel){
56712 if(this.tabs && (panel = this.getPanel(panel))){
56713 this.tabs.unhideTab(panel.getEl().id);
56717 clearPanels : function(){
56718 while(this.panels.getCount() > 0){
56719 this.remove(this.panels.first());
56724 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
56725 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
56726 * @param {Boolean} preservePanel Overrides the config preservePanel option
56727 * @return {Roo.ContentPanel} The panel that was removed
56729 remove : function(panel, preservePanel){
56730 panel = this.getPanel(panel);
56735 this.fireEvent("beforeremove", this, panel, e);
56736 if(e.cancel === true){
56739 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
56740 var panelId = panel.getId();
56741 this.panels.removeKey(panelId);
56743 document.body.appendChild(panel.getEl().dom);
56746 this.tabs.removeTab(panel.getEl().id);
56747 }else if (!preservePanel){
56748 this.bodyEl.dom.removeChild(panel.getEl().dom);
56750 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
56751 var p = this.panels.first();
56752 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
56753 tempEl.appendChild(p.getEl().dom);
56754 this.bodyEl.update("");
56755 this.bodyEl.dom.appendChild(p.getEl().dom);
56757 this.updateTitle(p.getTitle());
56759 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
56760 this.setActivePanel(p);
56762 panel.setRegion(null);
56763 if(this.activePanel == panel){
56764 this.activePanel = null;
56766 if(this.config.autoDestroy !== false && preservePanel !== true){
56767 try{panel.destroy();}catch(e){}
56769 this.fireEvent("panelremoved", this, panel);
56774 * Returns the TabPanel component used by this region
56775 * @return {Roo.TabPanel}
56777 getTabs : function(){
56781 createTool : function(parentEl, className){
56782 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
56783 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
56784 btn.addClassOnOver("x-layout-tools-button-over");
56789 * Ext JS Library 1.1.1
56790 * Copyright(c) 2006-2007, Ext JS, LLC.
56792 * Originally Released Under LGPL - original licence link has changed is not relivant.
56795 * <script type="text/javascript">
56801 * @class Roo.SplitLayoutRegion
56802 * @extends Roo.LayoutRegion
56803 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
56805 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
56806 this.cursor = cursor;
56807 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
56810 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
56811 splitTip : "Drag to resize.",
56812 collapsibleSplitTip : "Drag to resize. Double click to hide.",
56813 useSplitTips : false,
56815 applyConfig : function(config){
56816 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
56819 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
56820 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
56821 /** The SplitBar for this region
56822 * @type Roo.SplitBar */
56823 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
56824 this.split.on("moved", this.onSplitMove, this);
56825 this.split.useShim = config.useShim === true;
56826 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
56827 if(this.useSplitTips){
56828 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
56830 if(config.collapsible){
56831 this.split.el.on("dblclick", this.collapse, this);
56834 if(typeof config.minSize != "undefined"){
56835 this.split.minSize = config.minSize;
56837 if(typeof config.maxSize != "undefined"){
56838 this.split.maxSize = config.maxSize;
56840 if(config.hideWhenEmpty || config.hidden || config.collapsed){
56841 this.hideSplitter();
56846 getHMaxSize : function(){
56847 var cmax = this.config.maxSize || 10000;
56848 var center = this.mgr.getRegion("center");
56849 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
56852 getVMaxSize : function(){
56853 var cmax = this.config.maxSize || 10000;
56854 var center = this.mgr.getRegion("center");
56855 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
56858 onSplitMove : function(split, newSize){
56859 this.fireEvent("resized", this, newSize);
56863 * Returns the {@link Roo.SplitBar} for this region.
56864 * @return {Roo.SplitBar}
56866 getSplitBar : function(){
56871 this.hideSplitter();
56872 Roo.SplitLayoutRegion.superclass.hide.call(this);
56875 hideSplitter : function(){
56877 this.split.el.setLocation(-2000,-2000);
56878 this.split.el.hide();
56884 this.split.el.show();
56886 Roo.SplitLayoutRegion.superclass.show.call(this);
56889 beforeSlide: function(){
56890 if(Roo.isGecko){// firefox overflow auto bug workaround
56891 this.bodyEl.clip();
56893 this.tabs.bodyEl.clip();
56895 if(this.activePanel){
56896 this.activePanel.getEl().clip();
56898 if(this.activePanel.beforeSlide){
56899 this.activePanel.beforeSlide();
56905 afterSlide : function(){
56906 if(Roo.isGecko){// firefox overflow auto bug workaround
56907 this.bodyEl.unclip();
56909 this.tabs.bodyEl.unclip();
56911 if(this.activePanel){
56912 this.activePanel.getEl().unclip();
56913 if(this.activePanel.afterSlide){
56914 this.activePanel.afterSlide();
56920 initAutoHide : function(){
56921 if(this.autoHide !== false){
56922 if(!this.autoHideHd){
56923 var st = new Roo.util.DelayedTask(this.slideIn, this);
56924 this.autoHideHd = {
56925 "mouseout": function(e){
56926 if(!e.within(this.el, true)){
56930 "mouseover" : function(e){
56936 this.el.on(this.autoHideHd);
56940 clearAutoHide : function(){
56941 if(this.autoHide !== false){
56942 this.el.un("mouseout", this.autoHideHd.mouseout);
56943 this.el.un("mouseover", this.autoHideHd.mouseover);
56947 clearMonitor : function(){
56948 Roo.get(document).un("click", this.slideInIf, this);
56951 // these names are backwards but not changed for compat
56952 slideOut : function(){
56953 if(this.isSlid || this.el.hasActiveFx()){
56956 this.isSlid = true;
56957 if(this.collapseBtn){
56958 this.collapseBtn.hide();
56960 this.closeBtnState = this.closeBtn.getStyle('display');
56961 this.closeBtn.hide();
56963 this.stickBtn.show();
56966 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
56967 this.beforeSlide();
56968 this.el.setStyle("z-index", 10001);
56969 this.el.slideIn(this.getSlideAnchor(), {
56970 callback: function(){
56972 this.initAutoHide();
56973 Roo.get(document).on("click", this.slideInIf, this);
56974 this.fireEvent("slideshow", this);
56981 afterSlideIn : function(){
56982 this.clearAutoHide();
56983 this.isSlid = false;
56984 this.clearMonitor();
56985 this.el.setStyle("z-index", "");
56986 if(this.collapseBtn){
56987 this.collapseBtn.show();
56989 this.closeBtn.setStyle('display', this.closeBtnState);
56991 this.stickBtn.hide();
56993 this.fireEvent("slidehide", this);
56996 slideIn : function(cb){
56997 if(!this.isSlid || this.el.hasActiveFx()){
57001 this.isSlid = false;
57002 this.beforeSlide();
57003 this.el.slideOut(this.getSlideAnchor(), {
57004 callback: function(){
57005 this.el.setLeftTop(-10000, -10000);
57007 this.afterSlideIn();
57015 slideInIf : function(e){
57016 if(!e.within(this.el)){
57021 animateCollapse : function(){
57022 this.beforeSlide();
57023 this.el.setStyle("z-index", 20000);
57024 var anchor = this.getSlideAnchor();
57025 this.el.slideOut(anchor, {
57026 callback : function(){
57027 this.el.setStyle("z-index", "");
57028 this.collapsedEl.slideIn(anchor, {duration:.3});
57030 this.el.setLocation(-10000,-10000);
57032 this.fireEvent("collapsed", this);
57039 animateExpand : function(){
57040 this.beforeSlide();
57041 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
57042 this.el.setStyle("z-index", 20000);
57043 this.collapsedEl.hide({
57046 this.el.slideIn(this.getSlideAnchor(), {
57047 callback : function(){
57048 this.el.setStyle("z-index", "");
57051 this.split.el.show();
57053 this.fireEvent("invalidated", this);
57054 this.fireEvent("expanded", this);
57082 getAnchor : function(){
57083 return this.anchors[this.position];
57086 getCollapseAnchor : function(){
57087 return this.canchors[this.position];
57090 getSlideAnchor : function(){
57091 return this.sanchors[this.position];
57094 getAlignAdj : function(){
57095 var cm = this.cmargins;
57096 switch(this.position){
57112 getExpandAdj : function(){
57113 var c = this.collapsedEl, cm = this.cmargins;
57114 switch(this.position){
57116 return [-(cm.right+c.getWidth()+cm.left), 0];
57119 return [cm.right+c.getWidth()+cm.left, 0];
57122 return [0, -(cm.top+cm.bottom+c.getHeight())];
57125 return [0, cm.top+cm.bottom+c.getHeight()];
57131 * Ext JS Library 1.1.1
57132 * Copyright(c) 2006-2007, Ext JS, LLC.
57134 * Originally Released Under LGPL - original licence link has changed is not relivant.
57137 * <script type="text/javascript">
57140 * These classes are private internal classes
57142 Roo.CenterLayoutRegion = function(mgr, config){
57143 Roo.LayoutRegion.call(this, mgr, config, "center");
57144 this.visible = true;
57145 this.minWidth = config.minWidth || 20;
57146 this.minHeight = config.minHeight || 20;
57149 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
57151 // center panel can't be hidden
57155 // center panel can't be hidden
57158 getMinWidth: function(){
57159 return this.minWidth;
57162 getMinHeight: function(){
57163 return this.minHeight;
57168 Roo.NorthLayoutRegion = function(mgr, config){
57169 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
57171 this.split.placement = Roo.SplitBar.TOP;
57172 this.split.orientation = Roo.SplitBar.VERTICAL;
57173 this.split.el.addClass("x-layout-split-v");
57175 var size = config.initialSize || config.height;
57176 if(typeof size != "undefined"){
57177 this.el.setHeight(size);
57180 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
57181 orientation: Roo.SplitBar.VERTICAL,
57182 getBox : function(){
57183 if(this.collapsed){
57184 return this.collapsedEl.getBox();
57186 var box = this.el.getBox();
57188 box.height += this.split.el.getHeight();
57193 updateBox : function(box){
57194 if(this.split && !this.collapsed){
57195 box.height -= this.split.el.getHeight();
57196 this.split.el.setLeft(box.x);
57197 this.split.el.setTop(box.y+box.height);
57198 this.split.el.setWidth(box.width);
57200 if(this.collapsed){
57201 this.updateBody(box.width, null);
57203 Roo.LayoutRegion.prototype.updateBox.call(this, box);
57207 Roo.SouthLayoutRegion = function(mgr, config){
57208 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
57210 this.split.placement = Roo.SplitBar.BOTTOM;
57211 this.split.orientation = Roo.SplitBar.VERTICAL;
57212 this.split.el.addClass("x-layout-split-v");
57214 var size = config.initialSize || config.height;
57215 if(typeof size != "undefined"){
57216 this.el.setHeight(size);
57219 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
57220 orientation: Roo.SplitBar.VERTICAL,
57221 getBox : function(){
57222 if(this.collapsed){
57223 return this.collapsedEl.getBox();
57225 var box = this.el.getBox();
57227 var sh = this.split.el.getHeight();
57234 updateBox : function(box){
57235 if(this.split && !this.collapsed){
57236 var sh = this.split.el.getHeight();
57239 this.split.el.setLeft(box.x);
57240 this.split.el.setTop(box.y-sh);
57241 this.split.el.setWidth(box.width);
57243 if(this.collapsed){
57244 this.updateBody(box.width, null);
57246 Roo.LayoutRegion.prototype.updateBox.call(this, box);
57250 Roo.EastLayoutRegion = function(mgr, config){
57251 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
57253 this.split.placement = Roo.SplitBar.RIGHT;
57254 this.split.orientation = Roo.SplitBar.HORIZONTAL;
57255 this.split.el.addClass("x-layout-split-h");
57257 var size = config.initialSize || config.width;
57258 if(typeof size != "undefined"){
57259 this.el.setWidth(size);
57262 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
57263 orientation: Roo.SplitBar.HORIZONTAL,
57264 getBox : function(){
57265 if(this.collapsed){
57266 return this.collapsedEl.getBox();
57268 var box = this.el.getBox();
57270 var sw = this.split.el.getWidth();
57277 updateBox : function(box){
57278 if(this.split && !this.collapsed){
57279 var sw = this.split.el.getWidth();
57281 this.split.el.setLeft(box.x);
57282 this.split.el.setTop(box.y);
57283 this.split.el.setHeight(box.height);
57286 if(this.collapsed){
57287 this.updateBody(null, box.height);
57289 Roo.LayoutRegion.prototype.updateBox.call(this, box);
57293 Roo.WestLayoutRegion = function(mgr, config){
57294 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
57296 this.split.placement = Roo.SplitBar.LEFT;
57297 this.split.orientation = Roo.SplitBar.HORIZONTAL;
57298 this.split.el.addClass("x-layout-split-h");
57300 var size = config.initialSize || config.width;
57301 if(typeof size != "undefined"){
57302 this.el.setWidth(size);
57305 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
57306 orientation: Roo.SplitBar.HORIZONTAL,
57307 getBox : function(){
57308 if(this.collapsed){
57309 return this.collapsedEl.getBox();
57311 var box = this.el.getBox();
57313 box.width += this.split.el.getWidth();
57318 updateBox : function(box){
57319 if(this.split && !this.collapsed){
57320 var sw = this.split.el.getWidth();
57322 this.split.el.setLeft(box.x+box.width);
57323 this.split.el.setTop(box.y);
57324 this.split.el.setHeight(box.height);
57326 if(this.collapsed){
57327 this.updateBody(null, box.height);
57329 Roo.LayoutRegion.prototype.updateBox.call(this, box);
57334 * Ext JS Library 1.1.1
57335 * Copyright(c) 2006-2007, Ext JS, LLC.
57337 * Originally Released Under LGPL - original licence link has changed is not relivant.
57340 * <script type="text/javascript">
57345 * Private internal class for reading and applying state
57347 Roo.LayoutStateManager = function(layout){
57348 // default empty state
57357 Roo.LayoutStateManager.prototype = {
57358 init : function(layout, provider){
57359 this.provider = provider;
57360 var state = provider.get(layout.id+"-layout-state");
57362 var wasUpdating = layout.isUpdating();
57364 layout.beginUpdate();
57366 for(var key in state){
57367 if(typeof state[key] != "function"){
57368 var rstate = state[key];
57369 var r = layout.getRegion(key);
57372 r.resizeTo(rstate.size);
57374 if(rstate.collapsed == true){
57377 r.expand(null, true);
57383 layout.endUpdate();
57385 this.state = state;
57387 this.layout = layout;
57388 layout.on("regionresized", this.onRegionResized, this);
57389 layout.on("regioncollapsed", this.onRegionCollapsed, this);
57390 layout.on("regionexpanded", this.onRegionExpanded, this);
57393 storeState : function(){
57394 this.provider.set(this.layout.id+"-layout-state", this.state);
57397 onRegionResized : function(region, newSize){
57398 this.state[region.getPosition()].size = newSize;
57402 onRegionCollapsed : function(region){
57403 this.state[region.getPosition()].collapsed = true;
57407 onRegionExpanded : function(region){
57408 this.state[region.getPosition()].collapsed = false;
57413 * Ext JS Library 1.1.1
57414 * Copyright(c) 2006-2007, Ext JS, LLC.
57416 * Originally Released Under LGPL - original licence link has changed is not relivant.
57419 * <script type="text/javascript">
57422 * @class Roo.ContentPanel
57423 * @extends Roo.util.Observable
57424 * A basic ContentPanel element.
57425 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
57426 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
57427 * @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
57428 * @cfg {Boolean} closable True if the panel can be closed/removed
57429 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
57430 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
57431 * @cfg {Toolbar} toolbar A toolbar for this panel
57432 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
57433 * @cfg {String} title The title for this panel
57434 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
57435 * @cfg {String} url Calls {@link #setUrl} with this value
57436 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
57437 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
57438 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
57439 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
57442 * Create a new ContentPanel.
57443 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
57444 * @param {String/Object} config A string to set only the title or a config object
57445 * @param {String} content (optional) Set the HTML content for this panel
57446 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
57448 Roo.ContentPanel = function(el, config, content){
57452 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
57456 if (config && config.parentLayout) {
57457 el = config.parentLayout.el.createChild();
57460 if(el.autoCreate){ // xtype is available if this is called from factory
57464 this.el = Roo.get(el);
57465 if(!this.el && config && config.autoCreate){
57466 if(typeof config.autoCreate == "object"){
57467 if(!config.autoCreate.id){
57468 config.autoCreate.id = config.id||el;
57470 this.el = Roo.DomHelper.append(document.body,
57471 config.autoCreate, true);
57473 this.el = Roo.DomHelper.append(document.body,
57474 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
57477 this.closable = false;
57478 this.loaded = false;
57479 this.active = false;
57480 if(typeof config == "string"){
57481 this.title = config;
57483 Roo.apply(this, config);
57486 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
57487 this.wrapEl = this.el.wrap();
57488 this.toolbar.container = this.el.insertSibling(false, 'before');
57489 this.toolbar = new Roo.Toolbar(this.toolbar);
57492 // xtype created footer. - not sure if will work as we normally have to render first..
57493 if (this.footer && !this.footer.el && this.footer.xtype) {
57494 if (!this.wrapEl) {
57495 this.wrapEl = this.el.wrap();
57498 this.footer.container = this.wrapEl.createChild();
57500 this.footer = Roo.factory(this.footer, Roo);
57505 this.resizeEl = Roo.get(this.resizeEl, true);
57507 this.resizeEl = this.el;
57509 // handle view.xtype
57517 * Fires when this panel is activated.
57518 * @param {Roo.ContentPanel} this
57522 * @event deactivate
57523 * Fires when this panel is activated.
57524 * @param {Roo.ContentPanel} this
57526 "deactivate" : true,
57530 * Fires when this panel is resized if fitToFrame is true.
57531 * @param {Roo.ContentPanel} this
57532 * @param {Number} width The width after any component adjustments
57533 * @param {Number} height The height after any component adjustments
57539 * Fires when this tab is created
57540 * @param {Roo.ContentPanel} this
57551 if(this.autoScroll){
57552 this.resizeEl.setStyle("overflow", "auto");
57554 // fix randome scrolling
57555 this.el.on('scroll', function() {
57556 Roo.log('fix random scolling');
57557 this.scrollTo('top',0);
57560 content = content || this.content;
57562 this.setContent(content);
57564 if(config && config.url){
57565 this.setUrl(this.url, this.params, this.loadOnce);
57570 Roo.ContentPanel.superclass.constructor.call(this);
57572 if (this.view && typeof(this.view.xtype) != 'undefined') {
57573 this.view.el = this.el.appendChild(document.createElement("div"));
57574 this.view = Roo.factory(this.view);
57575 this.view.render && this.view.render(false, '');
57579 this.fireEvent('render', this);
57582 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
57584 setRegion : function(region){
57585 this.region = region;
57587 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
57589 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
57594 * Returns the toolbar for this Panel if one was configured.
57595 * @return {Roo.Toolbar}
57597 getToolbar : function(){
57598 return this.toolbar;
57601 setActiveState : function(active){
57602 this.active = active;
57604 this.fireEvent("deactivate", this);
57606 this.fireEvent("activate", this);
57610 * Updates this panel's element
57611 * @param {String} content The new content
57612 * @param {Boolean} loadScripts (optional) true to look for and process scripts
57614 setContent : function(content, loadScripts){
57615 this.el.update(content, loadScripts);
57618 ignoreResize : function(w, h){
57619 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
57622 this.lastSize = {width: w, height: h};
57627 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
57628 * @return {Roo.UpdateManager} The UpdateManager
57630 getUpdateManager : function(){
57631 return this.el.getUpdateManager();
57634 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
57635 * @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:
57638 url: "your-url.php",
57639 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
57640 callback: yourFunction,
57641 scope: yourObject, //(optional scope)
57644 text: "Loading...",
57649 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
57650 * 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.
57651 * @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}
57652 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
57653 * @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.
57654 * @return {Roo.ContentPanel} this
57657 var um = this.el.getUpdateManager();
57658 um.update.apply(um, arguments);
57664 * 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.
57665 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
57666 * @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)
57667 * @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)
57668 * @return {Roo.UpdateManager} The UpdateManager
57670 setUrl : function(url, params, loadOnce){
57671 if(this.refreshDelegate){
57672 this.removeListener("activate", this.refreshDelegate);
57674 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
57675 this.on("activate", this.refreshDelegate);
57676 return this.el.getUpdateManager();
57679 _handleRefresh : function(url, params, loadOnce){
57680 if(!loadOnce || !this.loaded){
57681 var updater = this.el.getUpdateManager();
57682 updater.update(url, params, this._setLoaded.createDelegate(this));
57686 _setLoaded : function(){
57687 this.loaded = true;
57691 * Returns this panel's id
57694 getId : function(){
57699 * Returns this panel's element - used by regiosn to add.
57700 * @return {Roo.Element}
57702 getEl : function(){
57703 return this.wrapEl || this.el;
57706 adjustForComponents : function(width, height)
57708 //Roo.log('adjustForComponents ');
57709 if(this.resizeEl != this.el){
57710 width -= this.el.getFrameWidth('lr');
57711 height -= this.el.getFrameWidth('tb');
57714 var te = this.toolbar.getEl();
57715 height -= te.getHeight();
57716 te.setWidth(width);
57719 var te = this.footer.getEl();
57720 Roo.log("footer:" + te.getHeight());
57722 height -= te.getHeight();
57723 te.setWidth(width);
57727 if(this.adjustments){
57728 width += this.adjustments[0];
57729 height += this.adjustments[1];
57731 return {"width": width, "height": height};
57734 setSize : function(width, height){
57735 if(this.fitToFrame && !this.ignoreResize(width, height)){
57736 if(this.fitContainer && this.resizeEl != this.el){
57737 this.el.setSize(width, height);
57739 var size = this.adjustForComponents(width, height);
57740 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
57741 this.fireEvent('resize', this, size.width, size.height);
57746 * Returns this panel's title
57749 getTitle : function(){
57754 * Set this panel's title
57755 * @param {String} title
57757 setTitle : function(title){
57758 this.title = title;
57760 this.region.updatePanelTitle(this, title);
57765 * Returns true is this panel was configured to be closable
57766 * @return {Boolean}
57768 isClosable : function(){
57769 return this.closable;
57772 beforeSlide : function(){
57774 this.resizeEl.clip();
57777 afterSlide : function(){
57779 this.resizeEl.unclip();
57783 * Force a content refresh from the URL specified in the {@link #setUrl} method.
57784 * Will fail silently if the {@link #setUrl} method has not been called.
57785 * This does not activate the panel, just updates its content.
57787 refresh : function(){
57788 if(this.refreshDelegate){
57789 this.loaded = false;
57790 this.refreshDelegate();
57795 * Destroys this panel
57797 destroy : function(){
57798 this.el.removeAllListeners();
57799 var tempEl = document.createElement("span");
57800 tempEl.appendChild(this.el.dom);
57801 tempEl.innerHTML = "";
57807 * form - if the content panel contains a form - this is a reference to it.
57808 * @type {Roo.form.Form}
57812 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
57813 * This contains a reference to it.
57819 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
57829 * @param {Object} cfg Xtype definition of item to add.
57832 addxtype : function(cfg) {
57834 if (cfg.xtype.match(/^Form$/)) {
57837 //if (this.footer) {
57838 // el = this.footer.container.insertSibling(false, 'before');
57840 el = this.el.createChild();
57843 this.form = new Roo.form.Form(cfg);
57846 if ( this.form.allItems.length) {
57847 this.form.render(el.dom);
57851 // should only have one of theses..
57852 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
57853 // views.. should not be just added - used named prop 'view''
57855 cfg.el = this.el.appendChild(document.createElement("div"));
57858 var ret = new Roo.factory(cfg);
57860 ret.render && ret.render(false, ''); // render blank..
57869 * @class Roo.GridPanel
57870 * @extends Roo.ContentPanel
57872 * Create a new GridPanel.
57873 * @param {Roo.grid.Grid} grid The grid for this panel
57874 * @param {String/Object} config A string to set only the panel's title, or a config object
57876 Roo.GridPanel = function(grid, config){
57879 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
57880 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
57882 this.wrapper.dom.appendChild(grid.getGridEl().dom);
57884 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
57887 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
57889 // xtype created footer. - not sure if will work as we normally have to render first..
57890 if (this.footer && !this.footer.el && this.footer.xtype) {
57892 this.footer.container = this.grid.getView().getFooterPanel(true);
57893 this.footer.dataSource = this.grid.dataSource;
57894 this.footer = Roo.factory(this.footer, Roo);
57898 grid.monitorWindowResize = false; // turn off autosizing
57899 grid.autoHeight = false;
57900 grid.autoWidth = false;
57902 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
57905 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
57906 getId : function(){
57907 return this.grid.id;
57911 * Returns the grid for this panel
57912 * @return {Roo.grid.Grid}
57914 getGrid : function(){
57918 setSize : function(width, height){
57919 if(!this.ignoreResize(width, height)){
57920 var grid = this.grid;
57921 var size = this.adjustForComponents(width, height);
57922 grid.getGridEl().setSize(size.width, size.height);
57927 beforeSlide : function(){
57928 this.grid.getView().scroller.clip();
57931 afterSlide : function(){
57932 this.grid.getView().scroller.unclip();
57935 destroy : function(){
57936 this.grid.destroy();
57938 Roo.GridPanel.superclass.destroy.call(this);
57944 * @class Roo.NestedLayoutPanel
57945 * @extends Roo.ContentPanel
57947 * Create a new NestedLayoutPanel.
57950 * @param {Roo.BorderLayout} layout The layout for this panel
57951 * @param {String/Object} config A string to set only the title or a config object
57953 Roo.NestedLayoutPanel = function(layout, config)
57955 // construct with only one argument..
57956 /* FIXME - implement nicer consturctors
57957 if (layout.layout) {
57959 layout = config.layout;
57960 delete config.layout;
57962 if (layout.xtype && !layout.getEl) {
57963 // then layout needs constructing..
57964 layout = Roo.factory(layout, Roo);
57969 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
57971 layout.monitorWindowResize = false; // turn off autosizing
57972 this.layout = layout;
57973 this.layout.getEl().addClass("x-layout-nested-layout");
57980 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
57982 setSize : function(width, height){
57983 if(!this.ignoreResize(width, height)){
57984 var size = this.adjustForComponents(width, height);
57985 var el = this.layout.getEl();
57986 el.setSize(size.width, size.height);
57987 var touch = el.dom.offsetWidth;
57988 this.layout.layout();
57989 // ie requires a double layout on the first pass
57990 if(Roo.isIE && !this.initialized){
57991 this.initialized = true;
57992 this.layout.layout();
57997 // activate all subpanels if not currently active..
57999 setActiveState : function(active){
58000 this.active = active;
58002 this.fireEvent("deactivate", this);
58006 this.fireEvent("activate", this);
58007 // not sure if this should happen before or after..
58008 if (!this.layout) {
58009 return; // should not happen..
58012 for (var r in this.layout.regions) {
58013 reg = this.layout.getRegion(r);
58014 if (reg.getActivePanel()) {
58015 //reg.showPanel(reg.getActivePanel()); // force it to activate..
58016 reg.setActivePanel(reg.getActivePanel());
58019 if (!reg.panels.length) {
58022 reg.showPanel(reg.getPanel(0));
58031 * Returns the nested BorderLayout for this panel
58032 * @return {Roo.BorderLayout}
58034 getLayout : function(){
58035 return this.layout;
58039 * Adds a xtype elements to the layout of the nested panel
58043 xtype : 'ContentPanel',
58050 xtype : 'NestedLayoutPanel',
58056 items : [ ... list of content panels or nested layout panels.. ]
58060 * @param {Object} cfg Xtype definition of item to add.
58062 addxtype : function(cfg) {
58063 return this.layout.addxtype(cfg);
58068 Roo.ScrollPanel = function(el, config, content){
58069 config = config || {};
58070 config.fitToFrame = true;
58071 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
58073 this.el.dom.style.overflow = "hidden";
58074 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
58075 this.el.removeClass("x-layout-inactive-content");
58076 this.el.on("mousewheel", this.onWheel, this);
58078 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
58079 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
58080 up.unselectable(); down.unselectable();
58081 up.on("click", this.scrollUp, this);
58082 down.on("click", this.scrollDown, this);
58083 up.addClassOnOver("x-scroller-btn-over");
58084 down.addClassOnOver("x-scroller-btn-over");
58085 up.addClassOnClick("x-scroller-btn-click");
58086 down.addClassOnClick("x-scroller-btn-click");
58087 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
58089 this.resizeEl = this.el;
58090 this.el = wrap; this.up = up; this.down = down;
58093 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
58095 wheelIncrement : 5,
58096 scrollUp : function(){
58097 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
58100 scrollDown : function(){
58101 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
58104 afterScroll : function(){
58105 var el = this.resizeEl;
58106 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
58107 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
58108 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
58111 setSize : function(){
58112 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
58113 this.afterScroll();
58116 onWheel : function(e){
58117 var d = e.getWheelDelta();
58118 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
58119 this.afterScroll();
58123 setContent : function(content, loadScripts){
58124 this.resizeEl.update(content, loadScripts);
58138 * @class Roo.TreePanel
58139 * @extends Roo.ContentPanel
58141 * Create a new TreePanel. - defaults to fit/scoll contents.
58142 * @param {String/Object} config A string to set only the panel's title, or a config object
58143 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
58145 Roo.TreePanel = function(config){
58146 var el = config.el;
58147 var tree = config.tree;
58148 delete config.tree;
58149 delete config.el; // hopefull!
58151 // wrapper for IE7 strict & safari scroll issue
58153 var treeEl = el.createChild();
58154 config.resizeEl = treeEl;
58158 Roo.TreePanel.superclass.constructor.call(this, el, config);
58161 this.tree = new Roo.tree.TreePanel(treeEl , tree);
58162 //console.log(tree);
58163 this.on('activate', function()
58165 if (this.tree.rendered) {
58168 //console.log('render tree');
58169 this.tree.render();
58171 // this should not be needed.. - it's actually the 'el' that resizes?
58172 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
58174 //this.on('resize', function (cp, w, h) {
58175 // this.tree.innerCt.setWidth(w);
58176 // this.tree.innerCt.setHeight(h);
58177 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
58184 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
58201 * Ext JS Library 1.1.1
58202 * Copyright(c) 2006-2007, Ext JS, LLC.
58204 * Originally Released Under LGPL - original licence link has changed is not relivant.
58207 * <script type="text/javascript">
58212 * @class Roo.ReaderLayout
58213 * @extends Roo.BorderLayout
58214 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
58215 * center region containing two nested regions (a top one for a list view and one for item preview below),
58216 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
58217 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
58218 * expedites the setup of the overall layout and regions for this common application style.
58221 var reader = new Roo.ReaderLayout();
58222 var CP = Roo.ContentPanel; // shortcut for adding
58224 reader.beginUpdate();
58225 reader.add("north", new CP("north", "North"));
58226 reader.add("west", new CP("west", {title: "West"}));
58227 reader.add("east", new CP("east", {title: "East"}));
58229 reader.regions.listView.add(new CP("listView", "List"));
58230 reader.regions.preview.add(new CP("preview", "Preview"));
58231 reader.endUpdate();
58234 * Create a new ReaderLayout
58235 * @param {Object} config Configuration options
58236 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
58237 * document.body if omitted)
58239 Roo.ReaderLayout = function(config, renderTo){
58240 var c = config || {size:{}};
58241 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
58242 north: c.north !== false ? Roo.apply({
58246 }, c.north) : false,
58247 west: c.west !== false ? Roo.apply({
58255 margins:{left:5,right:0,bottom:5,top:5},
58256 cmargins:{left:5,right:5,bottom:5,top:5}
58257 }, c.west) : false,
58258 east: c.east !== false ? Roo.apply({
58266 margins:{left:0,right:5,bottom:5,top:5},
58267 cmargins:{left:5,right:5,bottom:5,top:5}
58268 }, c.east) : false,
58269 center: Roo.apply({
58270 tabPosition: 'top',
58274 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
58278 this.el.addClass('x-reader');
58280 this.beginUpdate();
58282 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
58283 south: c.preview !== false ? Roo.apply({
58290 cmargins:{top:5,left:0, right:0, bottom:0}
58291 }, c.preview) : false,
58292 center: Roo.apply({
58298 this.add('center', new Roo.NestedLayoutPanel(inner,
58299 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
58303 this.regions.preview = inner.getRegion('south');
58304 this.regions.listView = inner.getRegion('center');
58307 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
58309 * Ext JS Library 1.1.1
58310 * Copyright(c) 2006-2007, Ext JS, LLC.
58312 * Originally Released Under LGPL - original licence link has changed is not relivant.
58315 * <script type="text/javascript">
58319 * @class Roo.grid.Grid
58320 * @extends Roo.util.Observable
58321 * This class represents the primary interface of a component based grid control.
58322 * <br><br>Usage:<pre><code>
58323 var grid = new Roo.grid.Grid("my-container-id", {
58326 selModel: mySelectionModel,
58327 autoSizeColumns: true,
58328 monitorWindowResize: false,
58329 trackMouseOver: true
58334 * <b>Common Problems:</b><br/>
58335 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
58336 * element will correct this<br/>
58337 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
58338 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
58339 * are unpredictable.<br/>
58340 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
58341 * grid to calculate dimensions/offsets.<br/>
58343 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58344 * The container MUST have some type of size defined for the grid to fill. The container will be
58345 * automatically set to position relative if it isn't already.
58346 * @param {Object} config A config object that sets properties on this grid.
58348 Roo.grid.Grid = function(container, config){
58349 // initialize the container
58350 this.container = Roo.get(container);
58351 this.container.update("");
58352 this.container.setStyle("overflow", "hidden");
58353 this.container.addClass('x-grid-container');
58355 this.id = this.container.id;
58357 Roo.apply(this, config);
58358 // check and correct shorthanded configs
58360 this.dataSource = this.ds;
58364 this.colModel = this.cm;
58368 this.selModel = this.sm;
58372 if (this.selModel) {
58373 this.selModel = Roo.factory(this.selModel, Roo.grid);
58374 this.sm = this.selModel;
58375 this.sm.xmodule = this.xmodule || false;
58377 if (typeof(this.colModel.config) == 'undefined') {
58378 this.colModel = new Roo.grid.ColumnModel(this.colModel);
58379 this.cm = this.colModel;
58380 this.cm.xmodule = this.xmodule || false;
58382 if (this.dataSource) {
58383 this.dataSource= Roo.factory(this.dataSource, Roo.data);
58384 this.ds = this.dataSource;
58385 this.ds.xmodule = this.xmodule || false;
58392 this.container.setWidth(this.width);
58396 this.container.setHeight(this.height);
58403 * The raw click event for the entire grid.
58404 * @param {Roo.EventObject} e
58409 * The raw dblclick event for the entire grid.
58410 * @param {Roo.EventObject} e
58414 * @event contextmenu
58415 * The raw contextmenu event for the entire grid.
58416 * @param {Roo.EventObject} e
58418 "contextmenu" : true,
58421 * The raw mousedown event for the entire grid.
58422 * @param {Roo.EventObject} e
58424 "mousedown" : true,
58427 * The raw mouseup event for the entire grid.
58428 * @param {Roo.EventObject} e
58433 * The raw mouseover event for the entire grid.
58434 * @param {Roo.EventObject} e
58436 "mouseover" : true,
58439 * The raw mouseout event for the entire grid.
58440 * @param {Roo.EventObject} e
58445 * The raw keypress event for the entire grid.
58446 * @param {Roo.EventObject} e
58451 * The raw keydown event for the entire grid.
58452 * @param {Roo.EventObject} e
58460 * Fires when a cell is clicked
58461 * @param {Grid} this
58462 * @param {Number} rowIndex
58463 * @param {Number} columnIndex
58464 * @param {Roo.EventObject} e
58466 "cellclick" : true,
58468 * @event celldblclick
58469 * Fires when a cell is double clicked
58470 * @param {Grid} this
58471 * @param {Number} rowIndex
58472 * @param {Number} columnIndex
58473 * @param {Roo.EventObject} e
58475 "celldblclick" : true,
58478 * Fires when a row is clicked
58479 * @param {Grid} this
58480 * @param {Number} rowIndex
58481 * @param {Roo.EventObject} e
58485 * @event rowdblclick
58486 * Fires when a row is double clicked
58487 * @param {Grid} this
58488 * @param {Number} rowIndex
58489 * @param {Roo.EventObject} e
58491 "rowdblclick" : true,
58493 * @event headerclick
58494 * Fires when a header is clicked
58495 * @param {Grid} this
58496 * @param {Number} columnIndex
58497 * @param {Roo.EventObject} e
58499 "headerclick" : true,
58501 * @event headerdblclick
58502 * Fires when a header cell is double clicked
58503 * @param {Grid} this
58504 * @param {Number} columnIndex
58505 * @param {Roo.EventObject} e
58507 "headerdblclick" : true,
58509 * @event rowcontextmenu
58510 * Fires when a row is right clicked
58511 * @param {Grid} this
58512 * @param {Number} rowIndex
58513 * @param {Roo.EventObject} e
58515 "rowcontextmenu" : true,
58517 * @event cellcontextmenu
58518 * Fires when a cell is right clicked
58519 * @param {Grid} this
58520 * @param {Number} rowIndex
58521 * @param {Number} cellIndex
58522 * @param {Roo.EventObject} e
58524 "cellcontextmenu" : true,
58526 * @event headercontextmenu
58527 * Fires when a header is right clicked
58528 * @param {Grid} this
58529 * @param {Number} columnIndex
58530 * @param {Roo.EventObject} e
58532 "headercontextmenu" : true,
58534 * @event bodyscroll
58535 * Fires when the body element is scrolled
58536 * @param {Number} scrollLeft
58537 * @param {Number} scrollTop
58539 "bodyscroll" : true,
58541 * @event columnresize
58542 * Fires when the user resizes a column
58543 * @param {Number} columnIndex
58544 * @param {Number} newSize
58546 "columnresize" : true,
58548 * @event columnmove
58549 * Fires when the user moves a column
58550 * @param {Number} oldIndex
58551 * @param {Number} newIndex
58553 "columnmove" : true,
58556 * Fires when row(s) start being dragged
58557 * @param {Grid} this
58558 * @param {Roo.GridDD} dd The drag drop object
58559 * @param {event} e The raw browser event
58561 "startdrag" : true,
58564 * Fires when a drag operation is complete
58565 * @param {Grid} this
58566 * @param {Roo.GridDD} dd The drag drop object
58567 * @param {event} e The raw browser event
58572 * Fires when dragged row(s) are dropped on a valid DD target
58573 * @param {Grid} this
58574 * @param {Roo.GridDD} dd The drag drop object
58575 * @param {String} targetId The target drag drop object
58576 * @param {event} e The raw browser event
58581 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
58582 * @param {Grid} this
58583 * @param {Roo.GridDD} dd The drag drop object
58584 * @param {String} targetId The target drag drop object
58585 * @param {event} e The raw browser event
58590 * Fires when the dragged row(s) first cross another DD target while being dragged
58591 * @param {Grid} this
58592 * @param {Roo.GridDD} dd The drag drop object
58593 * @param {String} targetId The target drag drop object
58594 * @param {event} e The raw browser event
58596 "dragenter" : true,
58599 * Fires when the dragged row(s) leave another DD target while being dragged
58600 * @param {Grid} this
58601 * @param {Roo.GridDD} dd The drag drop object
58602 * @param {String} targetId The target drag drop object
58603 * @param {event} e The raw browser event
58608 * Fires when a row is rendered, so you can change add a style to it.
58609 * @param {GridView} gridview The grid view
58610 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
58616 * Fires when the grid is rendered
58617 * @param {Grid} grid
58622 Roo.grid.Grid.superclass.constructor.call(this);
58624 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
58627 * @cfg {String} ddGroup - drag drop group.
58631 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
58633 minColumnWidth : 25,
58636 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
58637 * <b>on initial render.</b> It is more efficient to explicitly size the columns
58638 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
58640 autoSizeColumns : false,
58643 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
58645 autoSizeHeaders : true,
58648 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
58650 monitorWindowResize : true,
58653 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
58654 * rows measured to get a columns size. Default is 0 (all rows).
58656 maxRowsToMeasure : 0,
58659 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
58661 trackMouseOver : true,
58664 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
58668 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
58670 enableDragDrop : false,
58673 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
58675 enableColumnMove : true,
58678 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
58680 enableColumnHide : true,
58683 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
58685 enableRowHeightSync : false,
58688 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
58693 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
58695 autoHeight : false,
58698 * @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.
58700 autoExpandColumn : false,
58703 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
58706 autoExpandMin : 50,
58709 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
58711 autoExpandMax : 1000,
58714 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
58719 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
58723 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
58733 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
58734 * of a fixed width. Default is false.
58737 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
58740 * Called once after all setup has been completed and the grid is ready to be rendered.
58741 * @return {Roo.grid.Grid} this
58743 render : function()
58745 var c = this.container;
58746 // try to detect autoHeight/width mode
58747 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
58748 this.autoHeight = true;
58750 var view = this.getView();
58753 c.on("click", this.onClick, this);
58754 c.on("dblclick", this.onDblClick, this);
58755 c.on("contextmenu", this.onContextMenu, this);
58756 c.on("keydown", this.onKeyDown, this);
58758 c.on("touchstart", this.onTouchStart, this);
58761 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
58763 this.getSelectionModel().init(this);
58768 this.loadMask = new Roo.LoadMask(this.container,
58769 Roo.apply({store:this.dataSource}, this.loadMask));
58773 if (this.toolbar && this.toolbar.xtype) {
58774 this.toolbar.container = this.getView().getHeaderPanel(true);
58775 this.toolbar = new Roo.Toolbar(this.toolbar);
58777 if (this.footer && this.footer.xtype) {
58778 this.footer.dataSource = this.getDataSource();
58779 this.footer.container = this.getView().getFooterPanel(true);
58780 this.footer = Roo.factory(this.footer, Roo);
58782 if (this.dropTarget && this.dropTarget.xtype) {
58783 delete this.dropTarget.xtype;
58784 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
58788 this.rendered = true;
58789 this.fireEvent('render', this);
58794 * Reconfigures the grid to use a different Store and Column Model.
58795 * The View will be bound to the new objects and refreshed.
58796 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
58797 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
58799 reconfigure : function(dataSource, colModel){
58801 this.loadMask.destroy();
58802 this.loadMask = new Roo.LoadMask(this.container,
58803 Roo.apply({store:dataSource}, this.loadMask));
58805 this.view.bind(dataSource, colModel);
58806 this.dataSource = dataSource;
58807 this.colModel = colModel;
58808 this.view.refresh(true);
58812 onKeyDown : function(e){
58813 this.fireEvent("keydown", e);
58817 * Destroy this grid.
58818 * @param {Boolean} removeEl True to remove the element
58820 destroy : function(removeEl, keepListeners){
58822 this.loadMask.destroy();
58824 var c = this.container;
58825 c.removeAllListeners();
58826 this.view.destroy();
58827 this.colModel.purgeListeners();
58828 if(!keepListeners){
58829 this.purgeListeners();
58832 if(removeEl === true){
58838 processEvent : function(name, e){
58839 // does this fire select???
58840 //Roo.log('grid:processEvent ' + name);
58842 if (name != 'touchstart' ) {
58843 this.fireEvent(name, e);
58846 var t = e.getTarget();
58848 var header = v.findHeaderIndex(t);
58849 if(header !== false){
58850 var ename = name == 'touchstart' ? 'click' : name;
58852 this.fireEvent("header" + ename, this, header, e);
58854 var row = v.findRowIndex(t);
58855 var cell = v.findCellIndex(t);
58856 if (name == 'touchstart') {
58857 // first touch is always a click.
58858 // hopefull this happens after selection is updated.?
58861 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
58862 var cs = this.selModel.getSelectedCell();
58863 if (row == cs[0] && cell == cs[1]){
58867 if (typeof(this.selModel.getSelections) != 'undefined') {
58868 var cs = this.selModel.getSelections();
58869 var ds = this.dataSource;
58870 if (cs.length == 1 && ds.getAt(row) == cs[0]){
58881 this.fireEvent("row" + name, this, row, e);
58882 if(cell !== false){
58883 this.fireEvent("cell" + name, this, row, cell, e);
58890 onClick : function(e){
58891 this.processEvent("click", e);
58894 onTouchStart : function(e){
58895 this.processEvent("touchstart", e);
58899 onContextMenu : function(e, t){
58900 this.processEvent("contextmenu", e);
58904 onDblClick : function(e){
58905 this.processEvent("dblclick", e);
58909 walkCells : function(row, col, step, fn, scope){
58910 var cm = this.colModel, clen = cm.getColumnCount();
58911 var ds = this.dataSource, rlen = ds.getCount(), first = true;
58923 if(fn.call(scope || this, row, col, cm) === true){
58941 if(fn.call(scope || this, row, col, cm) === true){
58953 getSelections : function(){
58954 return this.selModel.getSelections();
58958 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
58959 * but if manual update is required this method will initiate it.
58961 autoSize : function(){
58963 this.view.layout();
58964 if(this.view.adjustForScroll){
58965 this.view.adjustForScroll();
58971 * Returns the grid's underlying element.
58972 * @return {Element} The element
58974 getGridEl : function(){
58975 return this.container;
58978 // private for compatibility, overridden by editor grid
58979 stopEditing : function(){},
58982 * Returns the grid's SelectionModel.
58983 * @return {SelectionModel}
58985 getSelectionModel : function(){
58986 if(!this.selModel){
58987 this.selModel = new Roo.grid.RowSelectionModel();
58989 return this.selModel;
58993 * Returns the grid's DataSource.
58994 * @return {DataSource}
58996 getDataSource : function(){
58997 return this.dataSource;
59001 * Returns the grid's ColumnModel.
59002 * @return {ColumnModel}
59004 getColumnModel : function(){
59005 return this.colModel;
59009 * Returns the grid's GridView object.
59010 * @return {GridView}
59012 getView : function(){
59014 this.view = new Roo.grid.GridView(this.viewConfig);
59019 * Called to get grid's drag proxy text, by default returns this.ddText.
59022 getDragDropText : function(){
59023 var count = this.selModel.getCount();
59024 return String.format(this.ddText, count, count == 1 ? '' : 's');
59028 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
59029 * %0 is replaced with the number of selected rows.
59032 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
59034 * Ext JS Library 1.1.1
59035 * Copyright(c) 2006-2007, Ext JS, LLC.
59037 * Originally Released Under LGPL - original licence link has changed is not relivant.
59040 * <script type="text/javascript">
59043 Roo.grid.AbstractGridView = function(){
59047 "beforerowremoved" : true,
59048 "beforerowsinserted" : true,
59049 "beforerefresh" : true,
59050 "rowremoved" : true,
59051 "rowsinserted" : true,
59052 "rowupdated" : true,
59055 Roo.grid.AbstractGridView.superclass.constructor.call(this);
59058 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
59059 rowClass : "x-grid-row",
59060 cellClass : "x-grid-cell",
59061 tdClass : "x-grid-td",
59062 hdClass : "x-grid-hd",
59063 splitClass : "x-grid-hd-split",
59065 init: function(grid){
59067 var cid = this.grid.getGridEl().id;
59068 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
59069 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
59070 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
59071 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
59074 getColumnRenderers : function(){
59075 var renderers = [];
59076 var cm = this.grid.colModel;
59077 var colCount = cm.getColumnCount();
59078 for(var i = 0; i < colCount; i++){
59079 renderers[i] = cm.getRenderer(i);
59084 getColumnIds : function(){
59086 var cm = this.grid.colModel;
59087 var colCount = cm.getColumnCount();
59088 for(var i = 0; i < colCount; i++){
59089 ids[i] = cm.getColumnId(i);
59094 getDataIndexes : function(){
59095 if(!this.indexMap){
59096 this.indexMap = this.buildIndexMap();
59098 return this.indexMap.colToData;
59101 getColumnIndexByDataIndex : function(dataIndex){
59102 if(!this.indexMap){
59103 this.indexMap = this.buildIndexMap();
59105 return this.indexMap.dataToCol[dataIndex];
59109 * Set a css style for a column dynamically.
59110 * @param {Number} colIndex The index of the column
59111 * @param {String} name The css property name
59112 * @param {String} value The css value
59114 setCSSStyle : function(colIndex, name, value){
59115 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
59116 Roo.util.CSS.updateRule(selector, name, value);
59119 generateRules : function(cm){
59120 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
59121 Roo.util.CSS.removeStyleSheet(rulesId);
59122 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59123 var cid = cm.getColumnId(i);
59124 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
59125 this.tdSelector, cid, " {\n}\n",
59126 this.hdSelector, cid, " {\n}\n",
59127 this.splitSelector, cid, " {\n}\n");
59129 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
59133 * Ext JS Library 1.1.1
59134 * Copyright(c) 2006-2007, Ext JS, LLC.
59136 * Originally Released Under LGPL - original licence link has changed is not relivant.
59139 * <script type="text/javascript">
59143 // This is a support class used internally by the Grid components
59144 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
59146 this.view = grid.getView();
59147 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
59148 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
59150 this.setHandleElId(Roo.id(hd));
59151 this.setOuterHandleElId(Roo.id(hd2));
59153 this.scroll = false;
59155 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
59157 getDragData : function(e){
59158 var t = Roo.lib.Event.getTarget(e);
59159 var h = this.view.findHeaderCell(t);
59161 return {ddel: h.firstChild, header:h};
59166 onInitDrag : function(e){
59167 this.view.headersDisabled = true;
59168 var clone = this.dragData.ddel.cloneNode(true);
59169 clone.id = Roo.id();
59170 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
59171 this.proxy.update(clone);
59175 afterValidDrop : function(){
59177 setTimeout(function(){
59178 v.headersDisabled = false;
59182 afterInvalidDrop : function(){
59184 setTimeout(function(){
59185 v.headersDisabled = false;
59191 * Ext JS Library 1.1.1
59192 * Copyright(c) 2006-2007, Ext JS, LLC.
59194 * Originally Released Under LGPL - original licence link has changed is not relivant.
59197 * <script type="text/javascript">
59200 // This is a support class used internally by the Grid components
59201 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
59203 this.view = grid.getView();
59204 // split the proxies so they don't interfere with mouse events
59205 this.proxyTop = Roo.DomHelper.append(document.body, {
59206 cls:"col-move-top", html:" "
59208 this.proxyBottom = Roo.DomHelper.append(document.body, {
59209 cls:"col-move-bottom", html:" "
59211 this.proxyTop.hide = this.proxyBottom.hide = function(){
59212 this.setLeftTop(-100,-100);
59213 this.setStyle("visibility", "hidden");
59215 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
59216 // temporarily disabled
59217 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
59218 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
59220 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
59221 proxyOffsets : [-4, -9],
59222 fly: Roo.Element.fly,
59224 getTargetFromEvent : function(e){
59225 var t = Roo.lib.Event.getTarget(e);
59226 var cindex = this.view.findCellIndex(t);
59227 if(cindex !== false){
59228 return this.view.getHeaderCell(cindex);
59233 nextVisible : function(h){
59234 var v = this.view, cm = this.grid.colModel;
59237 if(!cm.isHidden(v.getCellIndex(h))){
59245 prevVisible : function(h){
59246 var v = this.view, cm = this.grid.colModel;
59249 if(!cm.isHidden(v.getCellIndex(h))){
59257 positionIndicator : function(h, n, e){
59258 var x = Roo.lib.Event.getPageX(e);
59259 var r = Roo.lib.Dom.getRegion(n.firstChild);
59260 var px, pt, py = r.top + this.proxyOffsets[1];
59261 if((r.right - x) <= (r.right-r.left)/2){
59262 px = r.right+this.view.borderWidth;
59268 var oldIndex = this.view.getCellIndex(h);
59269 var newIndex = this.view.getCellIndex(n);
59271 if(this.grid.colModel.isFixed(newIndex)){
59275 var locked = this.grid.colModel.isLocked(newIndex);
59280 if(oldIndex < newIndex){
59283 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
59286 px += this.proxyOffsets[0];
59287 this.proxyTop.setLeftTop(px, py);
59288 this.proxyTop.show();
59289 if(!this.bottomOffset){
59290 this.bottomOffset = this.view.mainHd.getHeight();
59292 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
59293 this.proxyBottom.show();
59297 onNodeEnter : function(n, dd, e, data){
59298 if(data.header != n){
59299 this.positionIndicator(data.header, n, e);
59303 onNodeOver : function(n, dd, e, data){
59304 var result = false;
59305 if(data.header != n){
59306 result = this.positionIndicator(data.header, n, e);
59309 this.proxyTop.hide();
59310 this.proxyBottom.hide();
59312 return result ? this.dropAllowed : this.dropNotAllowed;
59315 onNodeOut : function(n, dd, e, data){
59316 this.proxyTop.hide();
59317 this.proxyBottom.hide();
59320 onNodeDrop : function(n, dd, e, data){
59321 var h = data.header;
59323 var cm = this.grid.colModel;
59324 var x = Roo.lib.Event.getPageX(e);
59325 var r = Roo.lib.Dom.getRegion(n.firstChild);
59326 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
59327 var oldIndex = this.view.getCellIndex(h);
59328 var newIndex = this.view.getCellIndex(n);
59329 var locked = cm.isLocked(newIndex);
59333 if(oldIndex < newIndex){
59336 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
59339 cm.setLocked(oldIndex, locked, true);
59340 cm.moveColumn(oldIndex, newIndex);
59341 this.grid.fireEvent("columnmove", oldIndex, newIndex);
59349 * Ext JS Library 1.1.1
59350 * Copyright(c) 2006-2007, Ext JS, LLC.
59352 * Originally Released Under LGPL - original licence link has changed is not relivant.
59355 * <script type="text/javascript">
59359 * @class Roo.grid.GridView
59360 * @extends Roo.util.Observable
59363 * @param {Object} config
59365 Roo.grid.GridView = function(config){
59366 Roo.grid.GridView.superclass.constructor.call(this);
59369 Roo.apply(this, config);
59372 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
59374 unselectable : 'unselectable="on"',
59375 unselectableCls : 'x-unselectable',
59378 rowClass : "x-grid-row",
59380 cellClass : "x-grid-col",
59382 tdClass : "x-grid-td",
59384 hdClass : "x-grid-hd",
59386 splitClass : "x-grid-split",
59388 sortClasses : ["sort-asc", "sort-desc"],
59390 enableMoveAnim : false,
59394 dh : Roo.DomHelper,
59396 fly : Roo.Element.fly,
59398 css : Roo.util.CSS,
59404 scrollIncrement : 22,
59406 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
59408 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
59410 bind : function(ds, cm){
59412 this.ds.un("load", this.onLoad, this);
59413 this.ds.un("datachanged", this.onDataChange, this);
59414 this.ds.un("add", this.onAdd, this);
59415 this.ds.un("remove", this.onRemove, this);
59416 this.ds.un("update", this.onUpdate, this);
59417 this.ds.un("clear", this.onClear, this);
59420 ds.on("load", this.onLoad, this);
59421 ds.on("datachanged", this.onDataChange, this);
59422 ds.on("add", this.onAdd, this);
59423 ds.on("remove", this.onRemove, this);
59424 ds.on("update", this.onUpdate, this);
59425 ds.on("clear", this.onClear, this);
59430 this.cm.un("widthchange", this.onColWidthChange, this);
59431 this.cm.un("headerchange", this.onHeaderChange, this);
59432 this.cm.un("hiddenchange", this.onHiddenChange, this);
59433 this.cm.un("columnmoved", this.onColumnMove, this);
59434 this.cm.un("columnlockchange", this.onColumnLock, this);
59437 this.generateRules(cm);
59438 cm.on("widthchange", this.onColWidthChange, this);
59439 cm.on("headerchange", this.onHeaderChange, this);
59440 cm.on("hiddenchange", this.onHiddenChange, this);
59441 cm.on("columnmoved", this.onColumnMove, this);
59442 cm.on("columnlockchange", this.onColumnLock, this);
59447 init: function(grid){
59448 Roo.grid.GridView.superclass.init.call(this, grid);
59450 this.bind(grid.dataSource, grid.colModel);
59452 grid.on("headerclick", this.handleHeaderClick, this);
59454 if(grid.trackMouseOver){
59455 grid.on("mouseover", this.onRowOver, this);
59456 grid.on("mouseout", this.onRowOut, this);
59458 grid.cancelTextSelection = function(){};
59459 this.gridId = grid.id;
59461 var tpls = this.templates || {};
59464 tpls.master = new Roo.Template(
59465 '<div class="x-grid" hidefocus="true">',
59466 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
59467 '<div class="x-grid-topbar"></div>',
59468 '<div class="x-grid-scroller"><div></div></div>',
59469 '<div class="x-grid-locked">',
59470 '<div class="x-grid-header">{lockedHeader}</div>',
59471 '<div class="x-grid-body">{lockedBody}</div>',
59473 '<div class="x-grid-viewport">',
59474 '<div class="x-grid-header">{header}</div>',
59475 '<div class="x-grid-body">{body}</div>',
59477 '<div class="x-grid-bottombar"></div>',
59479 '<div class="x-grid-resize-proxy"> </div>',
59482 tpls.master.disableformats = true;
59486 tpls.header = new Roo.Template(
59487 '<table border="0" cellspacing="0" cellpadding="0">',
59488 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
59491 tpls.header.disableformats = true;
59493 tpls.header.compile();
59496 tpls.hcell = new Roo.Template(
59497 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
59498 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
59501 tpls.hcell.disableFormats = true;
59503 tpls.hcell.compile();
59506 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
59507 this.unselectableCls + '" ' + this.unselectable +'> </div>');
59508 tpls.hsplit.disableFormats = true;
59510 tpls.hsplit.compile();
59513 tpls.body = new Roo.Template(
59514 '<table border="0" cellspacing="0" cellpadding="0">',
59515 "<tbody>{rows}</tbody>",
59518 tpls.body.disableFormats = true;
59520 tpls.body.compile();
59523 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
59524 tpls.row.disableFormats = true;
59526 tpls.row.compile();
59529 tpls.cell = new Roo.Template(
59530 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
59531 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
59532 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
59535 tpls.cell.disableFormats = true;
59537 tpls.cell.compile();
59539 this.templates = tpls;
59542 // remap these for backwards compat
59543 onColWidthChange : function(){
59544 this.updateColumns.apply(this, arguments);
59546 onHeaderChange : function(){
59547 this.updateHeaders.apply(this, arguments);
59549 onHiddenChange : function(){
59550 this.handleHiddenChange.apply(this, arguments);
59552 onColumnMove : function(){
59553 this.handleColumnMove.apply(this, arguments);
59555 onColumnLock : function(){
59556 this.handleLockChange.apply(this, arguments);
59559 onDataChange : function(){
59561 this.updateHeaderSortState();
59564 onClear : function(){
59568 onUpdate : function(ds, record){
59569 this.refreshRow(record);
59572 refreshRow : function(record){
59573 var ds = this.ds, index;
59574 if(typeof record == 'number'){
59576 record = ds.getAt(index);
59578 index = ds.indexOf(record);
59580 this.insertRows(ds, index, index, true);
59581 this.onRemove(ds, record, index+1, true);
59582 this.syncRowHeights(index, index);
59584 this.fireEvent("rowupdated", this, index, record);
59587 onAdd : function(ds, records, index){
59588 this.insertRows(ds, index, index + (records.length-1));
59591 onRemove : function(ds, record, index, isUpdate){
59592 if(isUpdate !== true){
59593 this.fireEvent("beforerowremoved", this, index, record);
59595 var bt = this.getBodyTable(), lt = this.getLockedTable();
59596 if(bt.rows[index]){
59597 bt.firstChild.removeChild(bt.rows[index]);
59599 if(lt.rows[index]){
59600 lt.firstChild.removeChild(lt.rows[index]);
59602 if(isUpdate !== true){
59603 this.stripeRows(index);
59604 this.syncRowHeights(index, index);
59606 this.fireEvent("rowremoved", this, index, record);
59610 onLoad : function(){
59611 this.scrollToTop();
59615 * Scrolls the grid to the top
59617 scrollToTop : function(){
59619 this.scroller.dom.scrollTop = 0;
59625 * Gets a panel in the header of the grid that can be used for toolbars etc.
59626 * After modifying the contents of this panel a call to grid.autoSize() may be
59627 * required to register any changes in size.
59628 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
59629 * @return Roo.Element
59631 getHeaderPanel : function(doShow){
59633 this.headerPanel.show();
59635 return this.headerPanel;
59639 * Gets a panel in the footer of the grid that can be used for toolbars etc.
59640 * After modifying the contents of this panel a call to grid.autoSize() may be
59641 * required to register any changes in size.
59642 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
59643 * @return Roo.Element
59645 getFooterPanel : function(doShow){
59647 this.footerPanel.show();
59649 return this.footerPanel;
59652 initElements : function(){
59653 var E = Roo.Element;
59654 var el = this.grid.getGridEl().dom.firstChild;
59655 var cs = el.childNodes;
59657 this.el = new E(el);
59659 this.focusEl = new E(el.firstChild);
59660 this.focusEl.swallowEvent("click", true);
59662 this.headerPanel = new E(cs[1]);
59663 this.headerPanel.enableDisplayMode("block");
59665 this.scroller = new E(cs[2]);
59666 this.scrollSizer = new E(this.scroller.dom.firstChild);
59668 this.lockedWrap = new E(cs[3]);
59669 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
59670 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
59672 this.mainWrap = new E(cs[4]);
59673 this.mainHd = new E(this.mainWrap.dom.firstChild);
59674 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
59676 this.footerPanel = new E(cs[5]);
59677 this.footerPanel.enableDisplayMode("block");
59679 this.resizeProxy = new E(cs[6]);
59681 this.headerSelector = String.format(
59682 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
59683 this.lockedHd.id, this.mainHd.id
59686 this.splitterSelector = String.format(
59687 '#{0} div.x-grid-split, #{1} div.x-grid-split',
59688 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
59691 idToCssName : function(s)
59693 return s.replace(/[^a-z0-9]+/ig, '-');
59696 getHeaderCell : function(index){
59697 return Roo.DomQuery.select(this.headerSelector)[index];
59700 getHeaderCellMeasure : function(index){
59701 return this.getHeaderCell(index).firstChild;
59704 getHeaderCellText : function(index){
59705 return this.getHeaderCell(index).firstChild.firstChild;
59708 getLockedTable : function(){
59709 return this.lockedBody.dom.firstChild;
59712 getBodyTable : function(){
59713 return this.mainBody.dom.firstChild;
59716 getLockedRow : function(index){
59717 return this.getLockedTable().rows[index];
59720 getRow : function(index){
59721 return this.getBodyTable().rows[index];
59724 getRowComposite : function(index){
59726 this.rowEl = new Roo.CompositeElementLite();
59728 var els = [], lrow, mrow;
59729 if(lrow = this.getLockedRow(index)){
59732 if(mrow = this.getRow(index)){
59735 this.rowEl.elements = els;
59739 * Gets the 'td' of the cell
59741 * @param {Integer} rowIndex row to select
59742 * @param {Integer} colIndex column to select
59746 getCell : function(rowIndex, colIndex){
59747 var locked = this.cm.getLockedCount();
59749 if(colIndex < locked){
59750 source = this.lockedBody.dom.firstChild;
59752 source = this.mainBody.dom.firstChild;
59753 colIndex -= locked;
59755 return source.rows[rowIndex].childNodes[colIndex];
59758 getCellText : function(rowIndex, colIndex){
59759 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
59762 getCellBox : function(cell){
59763 var b = this.fly(cell).getBox();
59764 if(Roo.isOpera){ // opera fails to report the Y
59765 b.y = cell.offsetTop + this.mainBody.getY();
59770 getCellIndex : function(cell){
59771 var id = String(cell.className).match(this.cellRE);
59773 return parseInt(id[1], 10);
59778 findHeaderIndex : function(n){
59779 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
59780 return r ? this.getCellIndex(r) : false;
59783 findHeaderCell : function(n){
59784 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
59785 return r ? r : false;
59788 findRowIndex : function(n){
59792 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
59793 return r ? r.rowIndex : false;
59796 findCellIndex : function(node){
59797 var stop = this.el.dom;
59798 while(node && node != stop){
59799 if(this.findRE.test(node.className)){
59800 return this.getCellIndex(node);
59802 node = node.parentNode;
59807 getColumnId : function(index){
59808 return this.cm.getColumnId(index);
59811 getSplitters : function()
59813 if(this.splitterSelector){
59814 return Roo.DomQuery.select(this.splitterSelector);
59820 getSplitter : function(index){
59821 return this.getSplitters()[index];
59824 onRowOver : function(e, t){
59826 if((row = this.findRowIndex(t)) !== false){
59827 this.getRowComposite(row).addClass("x-grid-row-over");
59831 onRowOut : function(e, t){
59833 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
59834 this.getRowComposite(row).removeClass("x-grid-row-over");
59838 renderHeaders : function(){
59840 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
59841 var cb = [], lb = [], sb = [], lsb = [], p = {};
59842 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59843 p.cellId = "x-grid-hd-0-" + i;
59844 p.splitId = "x-grid-csplit-0-" + i;
59845 p.id = cm.getColumnId(i);
59846 p.value = cm.getColumnHeader(i) || "";
59847 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
59848 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
59849 if(!cm.isLocked(i)){
59850 cb[cb.length] = ct.apply(p);
59851 sb[sb.length] = st.apply(p);
59853 lb[lb.length] = ct.apply(p);
59854 lsb[lsb.length] = st.apply(p);
59857 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
59858 ht.apply({cells: cb.join(""), splits:sb.join("")})];
59861 updateHeaders : function(){
59862 var html = this.renderHeaders();
59863 this.lockedHd.update(html[0]);
59864 this.mainHd.update(html[1]);
59868 * Focuses the specified row.
59869 * @param {Number} row The row index
59871 focusRow : function(row)
59873 //Roo.log('GridView.focusRow');
59874 var x = this.scroller.dom.scrollLeft;
59875 this.focusCell(row, 0, false);
59876 this.scroller.dom.scrollLeft = x;
59880 * Focuses the specified cell.
59881 * @param {Number} row The row index
59882 * @param {Number} col The column index
59883 * @param {Boolean} hscroll false to disable horizontal scrolling
59885 focusCell : function(row, col, hscroll)
59887 //Roo.log('GridView.focusCell');
59888 var el = this.ensureVisible(row, col, hscroll);
59889 this.focusEl.alignTo(el, "tl-tl");
59891 this.focusEl.focus();
59893 this.focusEl.focus.defer(1, this.focusEl);
59898 * Scrolls the specified cell into view
59899 * @param {Number} row The row index
59900 * @param {Number} col The column index
59901 * @param {Boolean} hscroll false to disable horizontal scrolling
59903 ensureVisible : function(row, col, hscroll)
59905 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
59906 //return null; //disable for testing.
59907 if(typeof row != "number"){
59908 row = row.rowIndex;
59910 if(row < 0 && row >= this.ds.getCount()){
59913 col = (col !== undefined ? col : 0);
59914 var cm = this.grid.colModel;
59915 while(cm.isHidden(col)){
59919 var el = this.getCell(row, col);
59923 var c = this.scroller.dom;
59925 var ctop = parseInt(el.offsetTop, 10);
59926 var cleft = parseInt(el.offsetLeft, 10);
59927 var cbot = ctop + el.offsetHeight;
59928 var cright = cleft + el.offsetWidth;
59930 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
59931 var stop = parseInt(c.scrollTop, 10);
59932 var sleft = parseInt(c.scrollLeft, 10);
59933 var sbot = stop + ch;
59934 var sright = sleft + c.clientWidth;
59936 Roo.log('GridView.ensureVisible:' +
59938 ' c.clientHeight:' + c.clientHeight +
59939 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
59947 c.scrollTop = ctop;
59948 //Roo.log("set scrolltop to ctop DISABLE?");
59949 }else if(cbot > sbot){
59950 //Roo.log("set scrolltop to cbot-ch");
59951 c.scrollTop = cbot-ch;
59954 if(hscroll !== false){
59956 c.scrollLeft = cleft;
59957 }else if(cright > sright){
59958 c.scrollLeft = cright-c.clientWidth;
59965 updateColumns : function(){
59966 this.grid.stopEditing();
59967 var cm = this.grid.colModel, colIds = this.getColumnIds();
59968 //var totalWidth = cm.getTotalWidth();
59970 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59971 //if(cm.isHidden(i)) continue;
59972 var w = cm.getColumnWidth(i);
59973 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
59974 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
59976 this.updateSplitters();
59979 generateRules : function(cm){
59980 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
59981 Roo.util.CSS.removeStyleSheet(rulesId);
59982 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59983 var cid = cm.getColumnId(i);
59985 if(cm.config[i].align){
59986 align = 'text-align:'+cm.config[i].align+';';
59989 if(cm.isHidden(i)){
59990 hidden = 'display:none;';
59992 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
59994 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
59995 this.hdSelector, cid, " {\n", align, width, "}\n",
59996 this.tdSelector, cid, " {\n",hidden,"\n}\n",
59997 this.splitSelector, cid, " {\n", hidden , "\n}\n");
59999 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
60002 updateSplitters : function(){
60003 var cm = this.cm, s = this.getSplitters();
60004 if(s){ // splitters not created yet
60005 var pos = 0, locked = true;
60006 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
60007 if(cm.isHidden(i)) {
60010 var w = cm.getColumnWidth(i); // make sure it's a number
60011 if(!cm.isLocked(i) && locked){
60016 s[i].style.left = (pos-this.splitOffset) + "px";
60021 handleHiddenChange : function(colModel, colIndex, hidden){
60023 this.hideColumn(colIndex);
60025 this.unhideColumn(colIndex);
60029 hideColumn : function(colIndex){
60030 var cid = this.getColumnId(colIndex);
60031 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
60032 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
60034 this.updateHeaders();
60036 this.updateSplitters();
60040 unhideColumn : function(colIndex){
60041 var cid = this.getColumnId(colIndex);
60042 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
60043 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
60046 this.updateHeaders();
60048 this.updateSplitters();
60052 insertRows : function(dm, firstRow, lastRow, isUpdate){
60053 if(firstRow == 0 && lastRow == dm.getCount()-1){
60057 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
60059 var s = this.getScrollState();
60060 var markup = this.renderRows(firstRow, lastRow);
60061 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
60062 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
60063 this.restoreScroll(s);
60065 this.fireEvent("rowsinserted", this, firstRow, lastRow);
60066 this.syncRowHeights(firstRow, lastRow);
60067 this.stripeRows(firstRow);
60073 bufferRows : function(markup, target, index){
60074 var before = null, trows = target.rows, tbody = target.tBodies[0];
60075 if(index < trows.length){
60076 before = trows[index];
60078 var b = document.createElement("div");
60079 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
60080 var rows = b.firstChild.rows;
60081 for(var i = 0, len = rows.length; i < len; i++){
60083 tbody.insertBefore(rows[0], before);
60085 tbody.appendChild(rows[0]);
60092 deleteRows : function(dm, firstRow, lastRow){
60093 if(dm.getRowCount()<1){
60094 this.fireEvent("beforerefresh", this);
60095 this.mainBody.update("");
60096 this.lockedBody.update("");
60097 this.fireEvent("refresh", this);
60099 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
60100 var bt = this.getBodyTable();
60101 var tbody = bt.firstChild;
60102 var rows = bt.rows;
60103 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
60104 tbody.removeChild(rows[firstRow]);
60106 this.stripeRows(firstRow);
60107 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
60111 updateRows : function(dataSource, firstRow, lastRow){
60112 var s = this.getScrollState();
60114 this.restoreScroll(s);
60117 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
60121 this.updateHeaderSortState();
60124 getScrollState : function(){
60126 var sb = this.scroller.dom;
60127 return {left: sb.scrollLeft, top: sb.scrollTop};
60130 stripeRows : function(startRow){
60131 if(!this.grid.stripeRows || this.ds.getCount() < 1){
60134 startRow = startRow || 0;
60135 var rows = this.getBodyTable().rows;
60136 var lrows = this.getLockedTable().rows;
60137 var cls = ' x-grid-row-alt ';
60138 for(var i = startRow, len = rows.length; i < len; i++){
60139 var row = rows[i], lrow = lrows[i];
60140 var isAlt = ((i+1) % 2 == 0);
60141 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
60142 if(isAlt == hasAlt){
60146 row.className += " x-grid-row-alt";
60148 row.className = row.className.replace("x-grid-row-alt", "");
60151 lrow.className = row.className;
60156 restoreScroll : function(state){
60157 //Roo.log('GridView.restoreScroll');
60158 var sb = this.scroller.dom;
60159 sb.scrollLeft = state.left;
60160 sb.scrollTop = state.top;
60164 syncScroll : function(){
60165 //Roo.log('GridView.syncScroll');
60166 var sb = this.scroller.dom;
60167 var sh = this.mainHd.dom;
60168 var bs = this.mainBody.dom;
60169 var lv = this.lockedBody.dom;
60170 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
60171 lv.scrollTop = bs.scrollTop = sb.scrollTop;
60174 handleScroll : function(e){
60176 var sb = this.scroller.dom;
60177 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
60181 handleWheel : function(e){
60182 var d = e.getWheelDelta();
60183 this.scroller.dom.scrollTop -= d*22;
60184 // set this here to prevent jumpy scrolling on large tables
60185 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
60189 renderRows : function(startRow, endRow){
60190 // pull in all the crap needed to render rows
60191 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
60192 var colCount = cm.getColumnCount();
60194 if(ds.getCount() < 1){
60198 // build a map for all the columns
60200 for(var i = 0; i < colCount; i++){
60201 var name = cm.getDataIndex(i);
60203 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
60204 renderer : cm.getRenderer(i),
60205 id : cm.getColumnId(i),
60206 locked : cm.isLocked(i),
60207 has_editor : cm.isCellEditable(i)
60211 startRow = startRow || 0;
60212 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
60214 // records to render
60215 var rs = ds.getRange(startRow, endRow);
60217 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
60220 // As much as I hate to duplicate code, this was branched because FireFox really hates
60221 // [].join("") on strings. The performance difference was substantial enough to
60222 // branch this function
60223 doRender : Roo.isGecko ?
60224 function(cs, rs, ds, startRow, colCount, stripe){
60225 var ts = this.templates, ct = ts.cell, rt = ts.row;
60227 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
60229 var hasListener = this.grid.hasListener('rowclass');
60231 for(var j = 0, len = rs.length; j < len; j++){
60232 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
60233 for(var i = 0; i < colCount; i++){
60235 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
60237 p.css = p.attr = "";
60238 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
60239 if(p.value == undefined || p.value === "") {
60240 p.value = " ";
60243 p.css += ' x-grid-editable-cell';
60245 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
60246 p.css += ' x-grid-dirty-cell';
60248 var markup = ct.apply(p);
60256 if(stripe && ((rowIndex+1) % 2 == 0)){
60257 alt.push("x-grid-row-alt")
60260 alt.push( " x-grid-dirty-row");
60263 if(this.getRowClass){
60264 alt.push(this.getRowClass(r, rowIndex));
60270 rowIndex : rowIndex,
60273 this.grid.fireEvent('rowclass', this, rowcfg);
60274 alt.push(rowcfg.rowClass);
60276 rp.alt = alt.join(" ");
60277 lbuf+= rt.apply(rp);
60279 buf+= rt.apply(rp);
60281 return [lbuf, buf];
60283 function(cs, rs, ds, startRow, colCount, stripe){
60284 var ts = this.templates, ct = ts.cell, rt = ts.row;
60286 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
60287 var hasListener = this.grid.hasListener('rowclass');
60290 for(var j = 0, len = rs.length; j < len; j++){
60291 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
60292 for(var i = 0; i < colCount; i++){
60294 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
60296 p.css = p.attr = "";
60297 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
60298 if(p.value == undefined || p.value === "") {
60299 p.value = " ";
60303 p.css += ' x-grid-editable-cell';
60305 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
60306 p.css += ' x-grid-dirty-cell'
60309 var markup = ct.apply(p);
60311 cb[cb.length] = markup;
60313 lcb[lcb.length] = markup;
60317 if(stripe && ((rowIndex+1) % 2 == 0)){
60318 alt.push( "x-grid-row-alt");
60321 alt.push(" x-grid-dirty-row");
60324 if(this.getRowClass){
60325 alt.push( this.getRowClass(r, rowIndex));
60331 rowIndex : rowIndex,
60334 this.grid.fireEvent('rowclass', this, rowcfg);
60335 alt.push(rowcfg.rowClass);
60338 rp.alt = alt.join(" ");
60339 rp.cells = lcb.join("");
60340 lbuf[lbuf.length] = rt.apply(rp);
60341 rp.cells = cb.join("");
60342 buf[buf.length] = rt.apply(rp);
60344 return [lbuf.join(""), buf.join("")];
60347 renderBody : function(){
60348 var markup = this.renderRows();
60349 var bt = this.templates.body;
60350 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
60354 * Refreshes the grid
60355 * @param {Boolean} headersToo
60357 refresh : function(headersToo){
60358 this.fireEvent("beforerefresh", this);
60359 this.grid.stopEditing();
60360 var result = this.renderBody();
60361 this.lockedBody.update(result[0]);
60362 this.mainBody.update(result[1]);
60363 if(headersToo === true){
60364 this.updateHeaders();
60365 this.updateColumns();
60366 this.updateSplitters();
60367 this.updateHeaderSortState();
60369 this.syncRowHeights();
60371 this.fireEvent("refresh", this);
60374 handleColumnMove : function(cm, oldIndex, newIndex){
60375 this.indexMap = null;
60376 var s = this.getScrollState();
60377 this.refresh(true);
60378 this.restoreScroll(s);
60379 this.afterMove(newIndex);
60382 afterMove : function(colIndex){
60383 if(this.enableMoveAnim && Roo.enableFx){
60384 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
60386 // if multisort - fix sortOrder, and reload..
60387 if (this.grid.dataSource.multiSort) {
60388 // the we can call sort again..
60389 var dm = this.grid.dataSource;
60390 var cm = this.grid.colModel;
60392 for(var i = 0; i < cm.config.length; i++ ) {
60394 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
60395 continue; // dont' bother, it's not in sort list or being set.
60398 so.push(cm.config[i].dataIndex);
60401 dm.load(dm.lastOptions);
60408 updateCell : function(dm, rowIndex, dataIndex){
60409 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
60410 if(typeof colIndex == "undefined"){ // not present in grid
60413 var cm = this.grid.colModel;
60414 var cell = this.getCell(rowIndex, colIndex);
60415 var cellText = this.getCellText(rowIndex, colIndex);
60418 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
60419 id : cm.getColumnId(colIndex),
60420 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
60422 var renderer = cm.getRenderer(colIndex);
60423 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
60424 if(typeof val == "undefined" || val === "") {
60427 cellText.innerHTML = val;
60428 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
60429 this.syncRowHeights(rowIndex, rowIndex);
60432 calcColumnWidth : function(colIndex, maxRowsToMeasure){
60434 if(this.grid.autoSizeHeaders){
60435 var h = this.getHeaderCellMeasure(colIndex);
60436 maxWidth = Math.max(maxWidth, h.scrollWidth);
60439 if(this.cm.isLocked(colIndex)){
60440 tb = this.getLockedTable();
60443 tb = this.getBodyTable();
60444 index = colIndex - this.cm.getLockedCount();
60447 var rows = tb.rows;
60448 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
60449 for(var i = 0; i < stopIndex; i++){
60450 var cell = rows[i].childNodes[index].firstChild;
60451 maxWidth = Math.max(maxWidth, cell.scrollWidth);
60454 return maxWidth + /*margin for error in IE*/ 5;
60457 * Autofit a column to its content.
60458 * @param {Number} colIndex
60459 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
60461 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
60462 if(this.cm.isHidden(colIndex)){
60463 return; // can't calc a hidden column
60466 var cid = this.cm.getColumnId(colIndex);
60467 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
60468 if(this.grid.autoSizeHeaders){
60469 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
60472 var newWidth = this.calcColumnWidth(colIndex);
60473 this.cm.setColumnWidth(colIndex,
60474 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
60475 if(!suppressEvent){
60476 this.grid.fireEvent("columnresize", colIndex, newWidth);
60481 * Autofits all columns to their content and then expands to fit any extra space in the grid
60483 autoSizeColumns : function(){
60484 var cm = this.grid.colModel;
60485 var colCount = cm.getColumnCount();
60486 for(var i = 0; i < colCount; i++){
60487 this.autoSizeColumn(i, true, true);
60489 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
60492 this.updateColumns();
60498 * Autofits all columns to the grid's width proportionate with their current size
60499 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
60501 fitColumns : function(reserveScrollSpace){
60502 var cm = this.grid.colModel;
60503 var colCount = cm.getColumnCount();
60507 for (i = 0; i < colCount; i++){
60508 if(!cm.isHidden(i) && !cm.isFixed(i)){
60509 w = cm.getColumnWidth(i);
60515 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
60516 if(reserveScrollSpace){
60519 var frac = (avail - cm.getTotalWidth())/width;
60520 while (cols.length){
60523 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
60525 this.updateColumns();
60529 onRowSelect : function(rowIndex){
60530 var row = this.getRowComposite(rowIndex);
60531 row.addClass("x-grid-row-selected");
60534 onRowDeselect : function(rowIndex){
60535 var row = this.getRowComposite(rowIndex);
60536 row.removeClass("x-grid-row-selected");
60539 onCellSelect : function(row, col){
60540 var cell = this.getCell(row, col);
60542 Roo.fly(cell).addClass("x-grid-cell-selected");
60546 onCellDeselect : function(row, col){
60547 var cell = this.getCell(row, col);
60549 Roo.fly(cell).removeClass("x-grid-cell-selected");
60553 updateHeaderSortState : function(){
60555 // sort state can be single { field: xxx, direction : yyy}
60556 // or { xxx=>ASC , yyy : DESC ..... }
60559 if (!this.ds.multiSort) {
60560 var state = this.ds.getSortState();
60564 mstate[state.field] = state.direction;
60565 // FIXME... - this is not used here.. but might be elsewhere..
60566 this.sortState = state;
60569 mstate = this.ds.sortToggle;
60571 //remove existing sort classes..
60573 var sc = this.sortClasses;
60574 var hds = this.el.select(this.headerSelector).removeClass(sc);
60576 for(var f in mstate) {
60578 var sortColumn = this.cm.findColumnIndex(f);
60580 if(sortColumn != -1){
60581 var sortDir = mstate[f];
60582 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
60591 handleHeaderClick : function(g, index,e){
60593 Roo.log("header click");
60596 // touch events on header are handled by context
60597 this.handleHdCtx(g,index,e);
60602 if(this.headersDisabled){
60605 var dm = g.dataSource, cm = g.colModel;
60606 if(!cm.isSortable(index)){
60611 if (dm.multiSort) {
60612 // update the sortOrder
60614 for(var i = 0; i < cm.config.length; i++ ) {
60616 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
60617 continue; // dont' bother, it's not in sort list or being set.
60620 so.push(cm.config[i].dataIndex);
60626 dm.sort(cm.getDataIndex(index));
60630 destroy : function(){
60632 this.colMenu.removeAll();
60633 Roo.menu.MenuMgr.unregister(this.colMenu);
60634 this.colMenu.getEl().remove();
60635 delete this.colMenu;
60638 this.hmenu.removeAll();
60639 Roo.menu.MenuMgr.unregister(this.hmenu);
60640 this.hmenu.getEl().remove();
60643 if(this.grid.enableColumnMove){
60644 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
60646 for(var dd in dds){
60647 if(!dds[dd].config.isTarget && dds[dd].dragElId){
60648 var elid = dds[dd].dragElId;
60650 Roo.get(elid).remove();
60651 } else if(dds[dd].config.isTarget){
60652 dds[dd].proxyTop.remove();
60653 dds[dd].proxyBottom.remove();
60656 if(Roo.dd.DDM.locationCache[dd]){
60657 delete Roo.dd.DDM.locationCache[dd];
60660 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
60663 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
60664 this.bind(null, null);
60665 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
60668 handleLockChange : function(){
60669 this.refresh(true);
60672 onDenyColumnLock : function(){
60676 onDenyColumnHide : function(){
60680 handleHdMenuClick : function(item){
60681 var index = this.hdCtxIndex;
60682 var cm = this.cm, ds = this.ds;
60685 ds.sort(cm.getDataIndex(index), "ASC");
60688 ds.sort(cm.getDataIndex(index), "DESC");
60691 var lc = cm.getLockedCount();
60692 if(cm.getColumnCount(true) <= lc+1){
60693 this.onDenyColumnLock();
60697 cm.setLocked(index, true, true);
60698 cm.moveColumn(index, lc);
60699 this.grid.fireEvent("columnmove", index, lc);
60701 cm.setLocked(index, true);
60705 var lc = cm.getLockedCount();
60706 if((lc-1) != index){
60707 cm.setLocked(index, false, true);
60708 cm.moveColumn(index, lc-1);
60709 this.grid.fireEvent("columnmove", index, lc-1);
60711 cm.setLocked(index, false);
60714 case 'wider': // used to expand cols on touch..
60716 var cw = cm.getColumnWidth(index);
60717 cw += (item.id == 'wider' ? 1 : -1) * 50;
60718 cw = Math.max(0, cw);
60719 cw = Math.min(cw,4000);
60720 cm.setColumnWidth(index, cw);
60724 index = cm.getIndexById(item.id.substr(4));
60726 if(item.checked && cm.getColumnCount(true) <= 1){
60727 this.onDenyColumnHide();
60730 cm.setHidden(index, item.checked);
60736 beforeColMenuShow : function(){
60737 var cm = this.cm, colCount = cm.getColumnCount();
60738 this.colMenu.removeAll();
60739 for(var i = 0; i < colCount; i++){
60740 this.colMenu.add(new Roo.menu.CheckItem({
60741 id: "col-"+cm.getColumnId(i),
60742 text: cm.getColumnHeader(i),
60743 checked: !cm.isHidden(i),
60749 handleHdCtx : function(g, index, e){
60751 var hd = this.getHeaderCell(index);
60752 this.hdCtxIndex = index;
60753 var ms = this.hmenu.items, cm = this.cm;
60754 ms.get("asc").setDisabled(!cm.isSortable(index));
60755 ms.get("desc").setDisabled(!cm.isSortable(index));
60756 if(this.grid.enableColLock !== false){
60757 ms.get("lock").setDisabled(cm.isLocked(index));
60758 ms.get("unlock").setDisabled(!cm.isLocked(index));
60760 this.hmenu.show(hd, "tl-bl");
60763 handleHdOver : function(e){
60764 var hd = this.findHeaderCell(e.getTarget());
60765 if(hd && !this.headersDisabled){
60766 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
60767 this.fly(hd).addClass("x-grid-hd-over");
60772 handleHdOut : function(e){
60773 var hd = this.findHeaderCell(e.getTarget());
60775 this.fly(hd).removeClass("x-grid-hd-over");
60779 handleSplitDblClick : function(e, t){
60780 var i = this.getCellIndex(t);
60781 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
60782 this.autoSizeColumn(i, true);
60787 render : function(){
60790 var colCount = cm.getColumnCount();
60792 if(this.grid.monitorWindowResize === true){
60793 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
60795 var header = this.renderHeaders();
60796 var body = this.templates.body.apply({rows:""});
60797 var html = this.templates.master.apply({
60800 lockedHeader: header[0],
60804 //this.updateColumns();
60806 this.grid.getGridEl().dom.innerHTML = html;
60808 this.initElements();
60810 // a kludge to fix the random scolling effect in webkit
60811 this.el.on("scroll", function() {
60812 this.el.dom.scrollTop=0; // hopefully not recursive..
60815 this.scroller.on("scroll", this.handleScroll, this);
60816 this.lockedBody.on("mousewheel", this.handleWheel, this);
60817 this.mainBody.on("mousewheel", this.handleWheel, this);
60819 this.mainHd.on("mouseover", this.handleHdOver, this);
60820 this.mainHd.on("mouseout", this.handleHdOut, this);
60821 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
60822 {delegate: "."+this.splitClass});
60824 this.lockedHd.on("mouseover", this.handleHdOver, this);
60825 this.lockedHd.on("mouseout", this.handleHdOut, this);
60826 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
60827 {delegate: "."+this.splitClass});
60829 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
60830 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
60833 this.updateSplitters();
60835 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
60836 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
60837 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
60840 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
60841 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
60843 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
60844 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
60846 if(this.grid.enableColLock !== false){
60847 this.hmenu.add('-',
60848 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
60849 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
60853 this.hmenu.add('-',
60854 {id:"wider", text: this.columnsWiderText},
60855 {id:"narrow", text: this.columnsNarrowText }
60861 if(this.grid.enableColumnHide !== false){
60863 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
60864 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
60865 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
60867 this.hmenu.add('-',
60868 {id:"columns", text: this.columnsText, menu: this.colMenu}
60871 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
60873 this.grid.on("headercontextmenu", this.handleHdCtx, this);
60876 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
60877 this.dd = new Roo.grid.GridDragZone(this.grid, {
60878 ddGroup : this.grid.ddGroup || 'GridDD'
60884 for(var i = 0; i < colCount; i++){
60885 if(cm.isHidden(i)){
60886 this.hideColumn(i);
60888 if(cm.config[i].align){
60889 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
60890 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
60894 this.updateHeaderSortState();
60896 this.beforeInitialResize();
60899 // two part rendering gives faster view to the user
60900 this.renderPhase2.defer(1, this);
60903 renderPhase2 : function(){
60904 // render the rows now
60906 if(this.grid.autoSizeColumns){
60907 this.autoSizeColumns();
60911 beforeInitialResize : function(){
60915 onColumnSplitterMoved : function(i, w){
60916 this.userResized = true;
60917 var cm = this.grid.colModel;
60918 cm.setColumnWidth(i, w, true);
60919 var cid = cm.getColumnId(i);
60920 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
60921 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
60922 this.updateSplitters();
60924 this.grid.fireEvent("columnresize", i, w);
60927 syncRowHeights : function(startIndex, endIndex){
60928 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
60929 startIndex = startIndex || 0;
60930 var mrows = this.getBodyTable().rows;
60931 var lrows = this.getLockedTable().rows;
60932 var len = mrows.length-1;
60933 endIndex = Math.min(endIndex || len, len);
60934 for(var i = startIndex; i <= endIndex; i++){
60935 var m = mrows[i], l = lrows[i];
60936 var h = Math.max(m.offsetHeight, l.offsetHeight);
60937 m.style.height = l.style.height = h + "px";
60942 layout : function(initialRender, is2ndPass){
60944 var auto = g.autoHeight;
60945 var scrollOffset = 16;
60946 var c = g.getGridEl(), cm = this.cm,
60947 expandCol = g.autoExpandColumn,
60949 //c.beginMeasure();
60951 if(!c.dom.offsetWidth){ // display:none?
60953 this.lockedWrap.show();
60954 this.mainWrap.show();
60959 var hasLock = this.cm.isLocked(0);
60961 var tbh = this.headerPanel.getHeight();
60962 var bbh = this.footerPanel.getHeight();
60965 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
60966 var newHeight = ch + c.getBorderWidth("tb");
60968 newHeight = Math.min(g.maxHeight, newHeight);
60970 c.setHeight(newHeight);
60974 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
60977 var s = this.scroller;
60979 var csize = c.getSize(true);
60981 this.el.setSize(csize.width, csize.height);
60983 this.headerPanel.setWidth(csize.width);
60984 this.footerPanel.setWidth(csize.width);
60986 var hdHeight = this.mainHd.getHeight();
60987 var vw = csize.width;
60988 var vh = csize.height - (tbh + bbh);
60992 var bt = this.getBodyTable();
60994 if(cm.getLockedCount() == cm.config.length){
60995 bt = this.getLockedTable();
60998 var ltWidth = hasLock ?
60999 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
61001 var scrollHeight = bt.offsetHeight;
61002 var scrollWidth = ltWidth + bt.offsetWidth;
61003 var vscroll = false, hscroll = false;
61005 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
61007 var lw = this.lockedWrap, mw = this.mainWrap;
61008 var lb = this.lockedBody, mb = this.mainBody;
61010 setTimeout(function(){
61011 var t = s.dom.offsetTop;
61012 var w = s.dom.clientWidth,
61013 h = s.dom.clientHeight;
61016 lw.setSize(ltWidth, h);
61018 mw.setLeftTop(ltWidth, t);
61019 mw.setSize(w-ltWidth, h);
61021 lb.setHeight(h-hdHeight);
61022 mb.setHeight(h-hdHeight);
61024 if(is2ndPass !== true && !gv.userResized && expandCol){
61025 // high speed resize without full column calculation
61027 var ci = cm.getIndexById(expandCol);
61029 ci = cm.findColumnIndex(expandCol);
61031 ci = Math.max(0, ci); // make sure it's got at least the first col.
61032 var expandId = cm.getColumnId(ci);
61033 var tw = cm.getTotalWidth(false);
61034 var currentWidth = cm.getColumnWidth(ci);
61035 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
61036 if(currentWidth != cw){
61037 cm.setColumnWidth(ci, cw, true);
61038 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
61039 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
61040 gv.updateSplitters();
61041 gv.layout(false, true);
61053 onWindowResize : function(){
61054 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
61060 appendFooter : function(parentEl){
61064 sortAscText : "Sort Ascending",
61065 sortDescText : "Sort Descending",
61066 lockText : "Lock Column",
61067 unlockText : "Unlock Column",
61068 columnsText : "Columns",
61070 columnsWiderText : "Wider",
61071 columnsNarrowText : "Thinner"
61075 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
61076 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
61077 this.proxy.el.addClass('x-grid3-col-dd');
61080 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
61081 handleMouseDown : function(e){
61085 callHandleMouseDown : function(e){
61086 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
61091 * Ext JS Library 1.1.1
61092 * Copyright(c) 2006-2007, Ext JS, LLC.
61094 * Originally Released Under LGPL - original licence link has changed is not relivant.
61097 * <script type="text/javascript">
61101 // This is a support class used internally by the Grid components
61102 Roo.grid.SplitDragZone = function(grid, hd, hd2){
61104 this.view = grid.getView();
61105 this.proxy = this.view.resizeProxy;
61106 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
61107 "gridSplitters" + this.grid.getGridEl().id, {
61108 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
61110 this.setHandleElId(Roo.id(hd));
61111 this.setOuterHandleElId(Roo.id(hd2));
61112 this.scroll = false;
61114 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
61115 fly: Roo.Element.fly,
61117 b4StartDrag : function(x, y){
61118 this.view.headersDisabled = true;
61119 this.proxy.setHeight(this.view.mainWrap.getHeight());
61120 var w = this.cm.getColumnWidth(this.cellIndex);
61121 var minw = Math.max(w-this.grid.minColumnWidth, 0);
61122 this.resetConstraints();
61123 this.setXConstraint(minw, 1000);
61124 this.setYConstraint(0, 0);
61125 this.minX = x - minw;
61126 this.maxX = x + 1000;
61128 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
61132 handleMouseDown : function(e){
61133 ev = Roo.EventObject.setEvent(e);
61134 var t = this.fly(ev.getTarget());
61135 if(t.hasClass("x-grid-split")){
61136 this.cellIndex = this.view.getCellIndex(t.dom);
61137 this.split = t.dom;
61138 this.cm = this.grid.colModel;
61139 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
61140 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
61145 endDrag : function(e){
61146 this.view.headersDisabled = false;
61147 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
61148 var diff = endX - this.startPos;
61149 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
61152 autoOffset : function(){
61153 this.setDelta(0,0);
61157 * Ext JS Library 1.1.1
61158 * Copyright(c) 2006-2007, Ext JS, LLC.
61160 * Originally Released Under LGPL - original licence link has changed is not relivant.
61163 * <script type="text/javascript">
61167 // This is a support class used internally by the Grid components
61168 Roo.grid.GridDragZone = function(grid, config){
61169 this.view = grid.getView();
61170 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
61171 if(this.view.lockedBody){
61172 this.setHandleElId(Roo.id(this.view.mainBody.dom));
61173 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
61175 this.scroll = false;
61177 this.ddel = document.createElement('div');
61178 this.ddel.className = 'x-grid-dd-wrap';
61181 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
61182 ddGroup : "GridDD",
61184 getDragData : function(e){
61185 var t = Roo.lib.Event.getTarget(e);
61186 var rowIndex = this.view.findRowIndex(t);
61187 var sm = this.grid.selModel;
61189 //Roo.log(rowIndex);
61191 if (sm.getSelectedCell) {
61192 // cell selection..
61193 if (!sm.getSelectedCell()) {
61196 if (rowIndex != sm.getSelectedCell()[0]) {
61202 if(rowIndex !== false){
61207 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
61209 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
61212 if (e.hasModifier()){
61213 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
61216 Roo.log("getDragData");
61221 rowIndex: rowIndex,
61222 selections:sm.getSelections ? sm.getSelections() : (
61223 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
61230 onInitDrag : function(e){
61231 var data = this.dragData;
61232 this.ddel.innerHTML = this.grid.getDragDropText();
61233 this.proxy.update(this.ddel);
61234 // fire start drag?
61237 afterRepair : function(){
61238 this.dragging = false;
61241 getRepairXY : function(e, data){
61245 onEndDrag : function(data, e){
61249 onValidDrop : function(dd, e, id){
61254 beforeInvalidDrop : function(e, id){
61259 * Ext JS Library 1.1.1
61260 * Copyright(c) 2006-2007, Ext JS, LLC.
61262 * Originally Released Under LGPL - original licence link has changed is not relivant.
61265 * <script type="text/javascript">
61270 * @class Roo.grid.ColumnModel
61271 * @extends Roo.util.Observable
61272 * This is the default implementation of a ColumnModel used by the Grid. It defines
61273 * the columns in the grid.
61276 var colModel = new Roo.grid.ColumnModel([
61277 {header: "Ticker", width: 60, sortable: true, locked: true},
61278 {header: "Company Name", width: 150, sortable: true},
61279 {header: "Market Cap.", width: 100, sortable: true},
61280 {header: "$ Sales", width: 100, sortable: true, renderer: money},
61281 {header: "Employees", width: 100, sortable: true, resizable: false}
61286 * The config options listed for this class are options which may appear in each
61287 * individual column definition.
61288 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
61290 * @param {Object} config An Array of column config objects. See this class's
61291 * config objects for details.
61293 Roo.grid.ColumnModel = function(config){
61295 * The config passed into the constructor
61297 this.config = config;
61300 // if no id, create one
61301 // if the column does not have a dataIndex mapping,
61302 // map it to the order it is in the config
61303 for(var i = 0, len = config.length; i < len; i++){
61305 if(typeof c.dataIndex == "undefined"){
61308 if(typeof c.renderer == "string"){
61309 c.renderer = Roo.util.Format[c.renderer];
61311 if(typeof c.id == "undefined"){
61314 if(c.editor && c.editor.xtype){
61315 c.editor = Roo.factory(c.editor, Roo.grid);
61317 if(c.editor && c.editor.isFormField){
61318 c.editor = new Roo.grid.GridEditor(c.editor);
61320 this.lookup[c.id] = c;
61324 * The width of columns which have no width specified (defaults to 100)
61327 this.defaultWidth = 100;
61330 * Default sortable of columns which have no sortable specified (defaults to false)
61333 this.defaultSortable = false;
61337 * @event widthchange
61338 * Fires when the width of a column changes.
61339 * @param {ColumnModel} this
61340 * @param {Number} columnIndex The column index
61341 * @param {Number} newWidth The new width
61343 "widthchange": true,
61345 * @event headerchange
61346 * Fires when the text of a header changes.
61347 * @param {ColumnModel} this
61348 * @param {Number} columnIndex The column index
61349 * @param {Number} newText The new header text
61351 "headerchange": true,
61353 * @event hiddenchange
61354 * Fires when a column is hidden or "unhidden".
61355 * @param {ColumnModel} this
61356 * @param {Number} columnIndex The column index
61357 * @param {Boolean} hidden true if hidden, false otherwise
61359 "hiddenchange": true,
61361 * @event columnmoved
61362 * Fires when a column is moved.
61363 * @param {ColumnModel} this
61364 * @param {Number} oldIndex
61365 * @param {Number} newIndex
61367 "columnmoved" : true,
61369 * @event columlockchange
61370 * Fires when a column's locked state is changed
61371 * @param {ColumnModel} this
61372 * @param {Number} colIndex
61373 * @param {Boolean} locked true if locked
61375 "columnlockchange" : true
61377 Roo.grid.ColumnModel.superclass.constructor.call(this);
61379 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
61381 * @cfg {String} header The header text to display in the Grid view.
61384 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
61385 * {@link Roo.data.Record} definition from which to draw the column's value. If not
61386 * specified, the column's index is used as an index into the Record's data Array.
61389 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
61390 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
61393 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
61394 * Defaults to the value of the {@link #defaultSortable} property.
61395 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
61398 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
61401 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
61404 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
61407 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
61410 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
61411 * given the cell's data value. See {@link #setRenderer}. If not specified, the
61412 * default renderer uses the raw data value. If an object is returned (bootstrap only)
61413 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
61416 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
61419 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
61422 * @cfg {String} cursor (Optional)
61425 * @cfg {String} tooltip (Optional)
61428 * @cfg {Number} xs (Optional)
61431 * @cfg {Number} sm (Optional)
61434 * @cfg {Number} md (Optional)
61437 * @cfg {Number} lg (Optional)
61440 * Returns the id of the column at the specified index.
61441 * @param {Number} index The column index
61442 * @return {String} the id
61444 getColumnId : function(index){
61445 return this.config[index].id;
61449 * Returns the column for a specified id.
61450 * @param {String} id The column id
61451 * @return {Object} the column
61453 getColumnById : function(id){
61454 return this.lookup[id];
61459 * Returns the column for a specified dataIndex.
61460 * @param {String} dataIndex The column dataIndex
61461 * @return {Object|Boolean} the column or false if not found
61463 getColumnByDataIndex: function(dataIndex){
61464 var index = this.findColumnIndex(dataIndex);
61465 return index > -1 ? this.config[index] : false;
61469 * Returns the index for a specified column id.
61470 * @param {String} id The column id
61471 * @return {Number} the index, or -1 if not found
61473 getIndexById : function(id){
61474 for(var i = 0, len = this.config.length; i < len; i++){
61475 if(this.config[i].id == id){
61483 * Returns the index for a specified column dataIndex.
61484 * @param {String} dataIndex The column dataIndex
61485 * @return {Number} the index, or -1 if not found
61488 findColumnIndex : function(dataIndex){
61489 for(var i = 0, len = this.config.length; i < len; i++){
61490 if(this.config[i].dataIndex == dataIndex){
61498 moveColumn : function(oldIndex, newIndex){
61499 var c = this.config[oldIndex];
61500 this.config.splice(oldIndex, 1);
61501 this.config.splice(newIndex, 0, c);
61502 this.dataMap = null;
61503 this.fireEvent("columnmoved", this, oldIndex, newIndex);
61506 isLocked : function(colIndex){
61507 return this.config[colIndex].locked === true;
61510 setLocked : function(colIndex, value, suppressEvent){
61511 if(this.isLocked(colIndex) == value){
61514 this.config[colIndex].locked = value;
61515 if(!suppressEvent){
61516 this.fireEvent("columnlockchange", this, colIndex, value);
61520 getTotalLockedWidth : function(){
61521 var totalWidth = 0;
61522 for(var i = 0; i < this.config.length; i++){
61523 if(this.isLocked(i) && !this.isHidden(i)){
61524 this.totalWidth += this.getColumnWidth(i);
61530 getLockedCount : function(){
61531 for(var i = 0, len = this.config.length; i < len; i++){
61532 if(!this.isLocked(i)){
61537 return this.config.length;
61541 * Returns the number of columns.
61544 getColumnCount : function(visibleOnly){
61545 if(visibleOnly === true){
61547 for(var i = 0, len = this.config.length; i < len; i++){
61548 if(!this.isHidden(i)){
61554 return this.config.length;
61558 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
61559 * @param {Function} fn
61560 * @param {Object} scope (optional)
61561 * @return {Array} result
61563 getColumnsBy : function(fn, scope){
61565 for(var i = 0, len = this.config.length; i < len; i++){
61566 var c = this.config[i];
61567 if(fn.call(scope||this, c, i) === true){
61575 * Returns true if the specified column is sortable.
61576 * @param {Number} col The column index
61577 * @return {Boolean}
61579 isSortable : function(col){
61580 if(typeof this.config[col].sortable == "undefined"){
61581 return this.defaultSortable;
61583 return this.config[col].sortable;
61587 * Returns the rendering (formatting) function defined for the column.
61588 * @param {Number} col The column index.
61589 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
61591 getRenderer : function(col){
61592 if(!this.config[col].renderer){
61593 return Roo.grid.ColumnModel.defaultRenderer;
61595 return this.config[col].renderer;
61599 * Sets the rendering (formatting) function for a column.
61600 * @param {Number} col The column index
61601 * @param {Function} fn The function to use to process the cell's raw data
61602 * to return HTML markup for the grid view. The render function is called with
61603 * the following parameters:<ul>
61604 * <li>Data value.</li>
61605 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
61606 * <li>css A CSS style string to apply to the table cell.</li>
61607 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
61608 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
61609 * <li>Row index</li>
61610 * <li>Column index</li>
61611 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
61613 setRenderer : function(col, fn){
61614 this.config[col].renderer = fn;
61618 * Returns the width for the specified column.
61619 * @param {Number} col The column index
61622 getColumnWidth : function(col){
61623 return this.config[col].width * 1 || this.defaultWidth;
61627 * Sets the width for a column.
61628 * @param {Number} col The column index
61629 * @param {Number} width The new width
61631 setColumnWidth : function(col, width, suppressEvent){
61632 this.config[col].width = width;
61633 this.totalWidth = null;
61634 if(!suppressEvent){
61635 this.fireEvent("widthchange", this, col, width);
61640 * Returns the total width of all columns.
61641 * @param {Boolean} includeHidden True to include hidden column widths
61644 getTotalWidth : function(includeHidden){
61645 if(!this.totalWidth){
61646 this.totalWidth = 0;
61647 for(var i = 0, len = this.config.length; i < len; i++){
61648 if(includeHidden || !this.isHidden(i)){
61649 this.totalWidth += this.getColumnWidth(i);
61653 return this.totalWidth;
61657 * Returns the header for the specified column.
61658 * @param {Number} col The column index
61661 getColumnHeader : function(col){
61662 return this.config[col].header;
61666 * Sets the header for a column.
61667 * @param {Number} col The column index
61668 * @param {String} header The new header
61670 setColumnHeader : function(col, header){
61671 this.config[col].header = header;
61672 this.fireEvent("headerchange", this, col, header);
61676 * Returns the tooltip for the specified column.
61677 * @param {Number} col The column index
61680 getColumnTooltip : function(col){
61681 return this.config[col].tooltip;
61684 * Sets the tooltip for a column.
61685 * @param {Number} col The column index
61686 * @param {String} tooltip The new tooltip
61688 setColumnTooltip : function(col, tooltip){
61689 this.config[col].tooltip = tooltip;
61693 * Returns the dataIndex for the specified column.
61694 * @param {Number} col The column index
61697 getDataIndex : function(col){
61698 return this.config[col].dataIndex;
61702 * Sets the dataIndex for a column.
61703 * @param {Number} col The column index
61704 * @param {Number} dataIndex The new dataIndex
61706 setDataIndex : function(col, dataIndex){
61707 this.config[col].dataIndex = dataIndex;
61713 * Returns true if the cell is editable.
61714 * @param {Number} colIndex The column index
61715 * @param {Number} rowIndex The row index - this is nto actually used..?
61716 * @return {Boolean}
61718 isCellEditable : function(colIndex, rowIndex){
61719 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
61723 * Returns the editor defined for the cell/column.
61724 * return false or null to disable editing.
61725 * @param {Number} colIndex The column index
61726 * @param {Number} rowIndex The row index
61729 getCellEditor : function(colIndex, rowIndex){
61730 return this.config[colIndex].editor;
61734 * Sets if a column is editable.
61735 * @param {Number} col The column index
61736 * @param {Boolean} editable True if the column is editable
61738 setEditable : function(col, editable){
61739 this.config[col].editable = editable;
61744 * Returns true if the column is hidden.
61745 * @param {Number} colIndex The column index
61746 * @return {Boolean}
61748 isHidden : function(colIndex){
61749 return this.config[colIndex].hidden;
61754 * Returns true if the column width cannot be changed
61756 isFixed : function(colIndex){
61757 return this.config[colIndex].fixed;
61761 * Returns true if the column can be resized
61762 * @return {Boolean}
61764 isResizable : function(colIndex){
61765 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
61768 * Sets if a column is hidden.
61769 * @param {Number} colIndex The column index
61770 * @param {Boolean} hidden True if the column is hidden
61772 setHidden : function(colIndex, hidden){
61773 this.config[colIndex].hidden = hidden;
61774 this.totalWidth = null;
61775 this.fireEvent("hiddenchange", this, colIndex, hidden);
61779 * Sets the editor for a column.
61780 * @param {Number} col The column index
61781 * @param {Object} editor The editor object
61783 setEditor : function(col, editor){
61784 this.config[col].editor = editor;
61788 Roo.grid.ColumnModel.defaultRenderer = function(value){
61789 if(typeof value == "string" && value.length < 1){
61795 // Alias for backwards compatibility
61796 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
61799 * Ext JS Library 1.1.1
61800 * Copyright(c) 2006-2007, Ext JS, LLC.
61802 * Originally Released Under LGPL - original licence link has changed is not relivant.
61805 * <script type="text/javascript">
61809 * @class Roo.grid.AbstractSelectionModel
61810 * @extends Roo.util.Observable
61811 * Abstract base class for grid SelectionModels. It provides the interface that should be
61812 * implemented by descendant classes. This class should not be directly instantiated.
61815 Roo.grid.AbstractSelectionModel = function(){
61816 this.locked = false;
61817 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
61820 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
61821 /** @ignore Called by the grid automatically. Do not call directly. */
61822 init : function(grid){
61828 * Locks the selections.
61831 this.locked = true;
61835 * Unlocks the selections.
61837 unlock : function(){
61838 this.locked = false;
61842 * Returns true if the selections are locked.
61843 * @return {Boolean}
61845 isLocked : function(){
61846 return this.locked;
61850 * Ext JS Library 1.1.1
61851 * Copyright(c) 2006-2007, Ext JS, LLC.
61853 * Originally Released Under LGPL - original licence link has changed is not relivant.
61856 * <script type="text/javascript">
61859 * @extends Roo.grid.AbstractSelectionModel
61860 * @class Roo.grid.RowSelectionModel
61861 * The default SelectionModel used by {@link Roo.grid.Grid}.
61862 * It supports multiple selections and keyboard selection/navigation.
61864 * @param {Object} config
61866 Roo.grid.RowSelectionModel = function(config){
61867 Roo.apply(this, config);
61868 this.selections = new Roo.util.MixedCollection(false, function(o){
61873 this.lastActive = false;
61877 * @event selectionchange
61878 * Fires when the selection changes
61879 * @param {SelectionModel} this
61881 "selectionchange" : true,
61883 * @event afterselectionchange
61884 * Fires after the selection changes (eg. by key press or clicking)
61885 * @param {SelectionModel} this
61887 "afterselectionchange" : true,
61889 * @event beforerowselect
61890 * Fires when a row is selected being selected, return false to cancel.
61891 * @param {SelectionModel} this
61892 * @param {Number} rowIndex The selected index
61893 * @param {Boolean} keepExisting False if other selections will be cleared
61895 "beforerowselect" : true,
61898 * Fires when a row is selected.
61899 * @param {SelectionModel} this
61900 * @param {Number} rowIndex The selected index
61901 * @param {Roo.data.Record} r The record
61903 "rowselect" : true,
61905 * @event rowdeselect
61906 * Fires when a row is deselected.
61907 * @param {SelectionModel} this
61908 * @param {Number} rowIndex The selected index
61910 "rowdeselect" : true
61912 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
61913 this.locked = false;
61916 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
61918 * @cfg {Boolean} singleSelect
61919 * True to allow selection of only one row at a time (defaults to false)
61921 singleSelect : false,
61924 initEvents : function(){
61926 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
61927 this.grid.on("mousedown", this.handleMouseDown, this);
61928 }else{ // allow click to work like normal
61929 this.grid.on("rowclick", this.handleDragableRowClick, this);
61932 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
61933 "up" : function(e){
61935 this.selectPrevious(e.shiftKey);
61936 }else if(this.last !== false && this.lastActive !== false){
61937 var last = this.last;
61938 this.selectRange(this.last, this.lastActive-1);
61939 this.grid.getView().focusRow(this.lastActive);
61940 if(last !== false){
61944 this.selectFirstRow();
61946 this.fireEvent("afterselectionchange", this);
61948 "down" : function(e){
61950 this.selectNext(e.shiftKey);
61951 }else if(this.last !== false && this.lastActive !== false){
61952 var last = this.last;
61953 this.selectRange(this.last, this.lastActive+1);
61954 this.grid.getView().focusRow(this.lastActive);
61955 if(last !== false){
61959 this.selectFirstRow();
61961 this.fireEvent("afterselectionchange", this);
61966 var view = this.grid.view;
61967 view.on("refresh", this.onRefresh, this);
61968 view.on("rowupdated", this.onRowUpdated, this);
61969 view.on("rowremoved", this.onRemove, this);
61973 onRefresh : function(){
61974 var ds = this.grid.dataSource, i, v = this.grid.view;
61975 var s = this.selections;
61976 s.each(function(r){
61977 if((i = ds.indexOfId(r.id)) != -1){
61979 s.add(ds.getAt(i)); // updating the selection relate data
61987 onRemove : function(v, index, r){
61988 this.selections.remove(r);
61992 onRowUpdated : function(v, index, r){
61993 if(this.isSelected(r)){
61994 v.onRowSelect(index);
62000 * @param {Array} records The records to select
62001 * @param {Boolean} keepExisting (optional) True to keep existing selections
62003 selectRecords : function(records, keepExisting){
62005 this.clearSelections();
62007 var ds = this.grid.dataSource;
62008 for(var i = 0, len = records.length; i < len; i++){
62009 this.selectRow(ds.indexOf(records[i]), true);
62014 * Gets the number of selected rows.
62017 getCount : function(){
62018 return this.selections.length;
62022 * Selects the first row in the grid.
62024 selectFirstRow : function(){
62029 * Select the last row.
62030 * @param {Boolean} keepExisting (optional) True to keep existing selections
62032 selectLastRow : function(keepExisting){
62033 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
62037 * Selects the row immediately following the last selected row.
62038 * @param {Boolean} keepExisting (optional) True to keep existing selections
62040 selectNext : function(keepExisting){
62041 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
62042 this.selectRow(this.last+1, keepExisting);
62043 this.grid.getView().focusRow(this.last);
62048 * Selects the row that precedes the last selected row.
62049 * @param {Boolean} keepExisting (optional) True to keep existing selections
62051 selectPrevious : function(keepExisting){
62053 this.selectRow(this.last-1, keepExisting);
62054 this.grid.getView().focusRow(this.last);
62059 * Returns the selected records
62060 * @return {Array} Array of selected records
62062 getSelections : function(){
62063 return [].concat(this.selections.items);
62067 * Returns the first selected record.
62070 getSelected : function(){
62071 return this.selections.itemAt(0);
62076 * Clears all selections.
62078 clearSelections : function(fast){
62083 var ds = this.grid.dataSource;
62084 var s = this.selections;
62085 s.each(function(r){
62086 this.deselectRow(ds.indexOfId(r.id));
62090 this.selections.clear();
62097 * Selects all rows.
62099 selectAll : function(){
62103 this.selections.clear();
62104 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
62105 this.selectRow(i, true);
62110 * Returns True if there is a selection.
62111 * @return {Boolean}
62113 hasSelection : function(){
62114 return this.selections.length > 0;
62118 * Returns True if the specified row is selected.
62119 * @param {Number/Record} record The record or index of the record to check
62120 * @return {Boolean}
62122 isSelected : function(index){
62123 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
62124 return (r && this.selections.key(r.id) ? true : false);
62128 * Returns True if the specified record id is selected.
62129 * @param {String} id The id of record to check
62130 * @return {Boolean}
62132 isIdSelected : function(id){
62133 return (this.selections.key(id) ? true : false);
62137 handleMouseDown : function(e, t){
62138 var view = this.grid.getView(), rowIndex;
62139 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
62142 if(e.shiftKey && this.last !== false){
62143 var last = this.last;
62144 this.selectRange(last, rowIndex, e.ctrlKey);
62145 this.last = last; // reset the last
62146 view.focusRow(rowIndex);
62148 var isSelected = this.isSelected(rowIndex);
62149 if(e.button !== 0 && isSelected){
62150 view.focusRow(rowIndex);
62151 }else if(e.ctrlKey && isSelected){
62152 this.deselectRow(rowIndex);
62153 }else if(!isSelected){
62154 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
62155 view.focusRow(rowIndex);
62158 this.fireEvent("afterselectionchange", this);
62161 handleDragableRowClick : function(grid, rowIndex, e)
62163 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
62164 this.selectRow(rowIndex, false);
62165 grid.view.focusRow(rowIndex);
62166 this.fireEvent("afterselectionchange", this);
62171 * Selects multiple rows.
62172 * @param {Array} rows Array of the indexes of the row to select
62173 * @param {Boolean} keepExisting (optional) True to keep existing selections
62175 selectRows : function(rows, keepExisting){
62177 this.clearSelections();
62179 for(var i = 0, len = rows.length; i < len; i++){
62180 this.selectRow(rows[i], true);
62185 * Selects a range of rows. All rows in between startRow and endRow are also selected.
62186 * @param {Number} startRow The index of the first row in the range
62187 * @param {Number} endRow The index of the last row in the range
62188 * @param {Boolean} keepExisting (optional) True to retain existing selections
62190 selectRange : function(startRow, endRow, keepExisting){
62195 this.clearSelections();
62197 if(startRow <= endRow){
62198 for(var i = startRow; i <= endRow; i++){
62199 this.selectRow(i, true);
62202 for(var i = startRow; i >= endRow; i--){
62203 this.selectRow(i, true);
62209 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
62210 * @param {Number} startRow The index of the first row in the range
62211 * @param {Number} endRow The index of the last row in the range
62213 deselectRange : function(startRow, endRow, preventViewNotify){
62217 for(var i = startRow; i <= endRow; i++){
62218 this.deselectRow(i, preventViewNotify);
62224 * @param {Number} row The index of the row to select
62225 * @param {Boolean} keepExisting (optional) True to keep existing selections
62227 selectRow : function(index, keepExisting, preventViewNotify){
62228 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
62231 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
62232 if(!keepExisting || this.singleSelect){
62233 this.clearSelections();
62235 var r = this.grid.dataSource.getAt(index);
62236 this.selections.add(r);
62237 this.last = this.lastActive = index;
62238 if(!preventViewNotify){
62239 this.grid.getView().onRowSelect(index);
62241 this.fireEvent("rowselect", this, index, r);
62242 this.fireEvent("selectionchange", this);
62248 * @param {Number} row The index of the row to deselect
62250 deselectRow : function(index, preventViewNotify){
62254 if(this.last == index){
62257 if(this.lastActive == index){
62258 this.lastActive = false;
62260 var r = this.grid.dataSource.getAt(index);
62261 this.selections.remove(r);
62262 if(!preventViewNotify){
62263 this.grid.getView().onRowDeselect(index);
62265 this.fireEvent("rowdeselect", this, index);
62266 this.fireEvent("selectionchange", this);
62270 restoreLast : function(){
62272 this.last = this._last;
62277 acceptsNav : function(row, col, cm){
62278 return !cm.isHidden(col) && cm.isCellEditable(col, row);
62282 onEditorKey : function(field, e){
62283 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
62288 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
62290 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
62292 }else if(k == e.ENTER && !e.ctrlKey){
62296 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
62298 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
62300 }else if(k == e.ESC){
62304 g.startEditing(newCell[0], newCell[1]);
62309 * Ext JS Library 1.1.1
62310 * Copyright(c) 2006-2007, Ext JS, LLC.
62312 * Originally Released Under LGPL - original licence link has changed is not relivant.
62315 * <script type="text/javascript">
62318 * @class Roo.grid.CellSelectionModel
62319 * @extends Roo.grid.AbstractSelectionModel
62320 * This class provides the basic implementation for cell selection in a grid.
62322 * @param {Object} config The object containing the configuration of this model.
62323 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
62325 Roo.grid.CellSelectionModel = function(config){
62326 Roo.apply(this, config);
62328 this.selection = null;
62332 * @event beforerowselect
62333 * Fires before a cell is selected.
62334 * @param {SelectionModel} this
62335 * @param {Number} rowIndex The selected row index
62336 * @param {Number} colIndex The selected cell index
62338 "beforecellselect" : true,
62340 * @event cellselect
62341 * Fires when a cell is selected.
62342 * @param {SelectionModel} this
62343 * @param {Number} rowIndex The selected row index
62344 * @param {Number} colIndex The selected cell index
62346 "cellselect" : true,
62348 * @event selectionchange
62349 * Fires when the active selection changes.
62350 * @param {SelectionModel} this
62351 * @param {Object} selection null for no selection or an object (o) with two properties
62353 <li>o.record: the record object for the row the selection is in</li>
62354 <li>o.cell: An array of [rowIndex, columnIndex]</li>
62357 "selectionchange" : true,
62360 * Fires when the tab (or enter) was pressed on the last editable cell
62361 * You can use this to trigger add new row.
62362 * @param {SelectionModel} this
62366 * @event beforeeditnext
62367 * Fires before the next editable sell is made active
62368 * You can use this to skip to another cell or fire the tabend
62369 * if you set cell to false
62370 * @param {Object} eventdata object : { cell : [ row, col ] }
62372 "beforeeditnext" : true
62374 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
62377 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
62379 enter_is_tab: false,
62382 initEvents : function(){
62383 this.grid.on("mousedown", this.handleMouseDown, this);
62384 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
62385 var view = this.grid.view;
62386 view.on("refresh", this.onViewChange, this);
62387 view.on("rowupdated", this.onRowUpdated, this);
62388 view.on("beforerowremoved", this.clearSelections, this);
62389 view.on("beforerowsinserted", this.clearSelections, this);
62390 if(this.grid.isEditor){
62391 this.grid.on("beforeedit", this.beforeEdit, this);
62396 beforeEdit : function(e){
62397 this.select(e.row, e.column, false, true, e.record);
62401 onRowUpdated : function(v, index, r){
62402 if(this.selection && this.selection.record == r){
62403 v.onCellSelect(index, this.selection.cell[1]);
62408 onViewChange : function(){
62409 this.clearSelections(true);
62413 * Returns the currently selected cell,.
62414 * @return {Array} The selected cell (row, column) or null if none selected.
62416 getSelectedCell : function(){
62417 return this.selection ? this.selection.cell : null;
62421 * Clears all selections.
62422 * @param {Boolean} true to prevent the gridview from being notified about the change.
62424 clearSelections : function(preventNotify){
62425 var s = this.selection;
62427 if(preventNotify !== true){
62428 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
62430 this.selection = null;
62431 this.fireEvent("selectionchange", this, null);
62436 * Returns true if there is a selection.
62437 * @return {Boolean}
62439 hasSelection : function(){
62440 return this.selection ? true : false;
62444 handleMouseDown : function(e, t){
62445 var v = this.grid.getView();
62446 if(this.isLocked()){
62449 var row = v.findRowIndex(t);
62450 var cell = v.findCellIndex(t);
62451 if(row !== false && cell !== false){
62452 this.select(row, cell);
62458 * @param {Number} rowIndex
62459 * @param {Number} collIndex
62461 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
62462 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
62463 this.clearSelections();
62464 r = r || this.grid.dataSource.getAt(rowIndex);
62467 cell : [rowIndex, colIndex]
62469 if(!preventViewNotify){
62470 var v = this.grid.getView();
62471 v.onCellSelect(rowIndex, colIndex);
62472 if(preventFocus !== true){
62473 v.focusCell(rowIndex, colIndex);
62476 this.fireEvent("cellselect", this, rowIndex, colIndex);
62477 this.fireEvent("selectionchange", this, this.selection);
62482 isSelectable : function(rowIndex, colIndex, cm){
62483 return !cm.isHidden(colIndex);
62487 handleKeyDown : function(e){
62488 //Roo.log('Cell Sel Model handleKeyDown');
62489 if(!e.isNavKeyPress()){
62492 var g = this.grid, s = this.selection;
62495 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
62497 this.select(cell[0], cell[1]);
62502 var walk = function(row, col, step){
62503 return g.walkCells(row, col, step, sm.isSelectable, sm);
62505 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
62512 // handled by onEditorKey
62513 if (g.isEditor && g.editing) {
62517 newCell = walk(r, c-1, -1);
62519 newCell = walk(r, c+1, 1);
62524 newCell = walk(r+1, c, 1);
62528 newCell = walk(r-1, c, -1);
62532 newCell = walk(r, c+1, 1);
62536 newCell = walk(r, c-1, -1);
62541 if(g.isEditor && !g.editing){
62542 g.startEditing(r, c);
62551 this.select(newCell[0], newCell[1]);
62557 acceptsNav : function(row, col, cm){
62558 return !cm.isHidden(col) && cm.isCellEditable(col, row);
62562 * @param {Number} field (not used) - as it's normally used as a listener
62563 * @param {Number} e - event - fake it by using
62565 * var e = Roo.EventObjectImpl.prototype;
62566 * e.keyCode = e.TAB
62570 onEditorKey : function(field, e){
62572 var k = e.getKey(),
62575 ed = g.activeEditor,
62577 ///Roo.log('onEditorKey' + k);
62580 if (this.enter_is_tab && k == e.ENTER) {
62586 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
62588 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
62594 } else if(k == e.ENTER && !e.ctrlKey){
62597 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
62599 } else if(k == e.ESC){
62604 var ecall = { cell : newCell, forward : forward };
62605 this.fireEvent('beforeeditnext', ecall );
62606 newCell = ecall.cell;
62607 forward = ecall.forward;
62611 //Roo.log('next cell after edit');
62612 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
62613 } else if (forward) {
62614 // tabbed past last
62615 this.fireEvent.defer(100, this, ['tabend',this]);
62620 * Ext JS Library 1.1.1
62621 * Copyright(c) 2006-2007, Ext JS, LLC.
62623 * Originally Released Under LGPL - original licence link has changed is not relivant.
62626 * <script type="text/javascript">
62630 * @class Roo.grid.EditorGrid
62631 * @extends Roo.grid.Grid
62632 * Class for creating and editable grid.
62633 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
62634 * The container MUST have some type of size defined for the grid to fill. The container will be
62635 * automatically set to position relative if it isn't already.
62636 * @param {Object} dataSource The data model to bind to
62637 * @param {Object} colModel The column model with info about this grid's columns
62639 Roo.grid.EditorGrid = function(container, config){
62640 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
62641 this.getGridEl().addClass("xedit-grid");
62643 if(!this.selModel){
62644 this.selModel = new Roo.grid.CellSelectionModel();
62647 this.activeEditor = null;
62651 * @event beforeedit
62652 * Fires before cell editing is triggered. The edit event object has the following properties <br />
62653 * <ul style="padding:5px;padding-left:16px;">
62654 * <li>grid - This grid</li>
62655 * <li>record - The record being edited</li>
62656 * <li>field - The field name being edited</li>
62657 * <li>value - The value for the field being edited.</li>
62658 * <li>row - The grid row index</li>
62659 * <li>column - The grid column index</li>
62660 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
62662 * @param {Object} e An edit event (see above for description)
62664 "beforeedit" : true,
62667 * Fires after a cell is edited. <br />
62668 * <ul style="padding:5px;padding-left:16px;">
62669 * <li>grid - This grid</li>
62670 * <li>record - The record being edited</li>
62671 * <li>field - The field name being edited</li>
62672 * <li>value - The value being set</li>
62673 * <li>originalValue - The original value for the field, before the edit.</li>
62674 * <li>row - The grid row index</li>
62675 * <li>column - The grid column index</li>
62677 * @param {Object} e An edit event (see above for description)
62679 "afteredit" : true,
62681 * @event validateedit
62682 * Fires after a cell is edited, but before the value is set in the record.
62683 * You can use this to modify the value being set in the field, Return false
62684 * to cancel the change. The edit event object has the following properties <br />
62685 * <ul style="padding:5px;padding-left:16px;">
62686 * <li>editor - This editor</li>
62687 * <li>grid - This grid</li>
62688 * <li>record - The record being edited</li>
62689 * <li>field - The field name being edited</li>
62690 * <li>value - The value being set</li>
62691 * <li>originalValue - The original value for the field, before the edit.</li>
62692 * <li>row - The grid row index</li>
62693 * <li>column - The grid column index</li>
62694 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
62696 * @param {Object} e An edit event (see above for description)
62698 "validateedit" : true
62700 this.on("bodyscroll", this.stopEditing, this);
62701 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
62704 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
62706 * @cfg {Number} clicksToEdit
62707 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
62714 trackMouseOver: false, // causes very odd FF errors
62716 onCellDblClick : function(g, row, col){
62717 this.startEditing(row, col);
62720 onEditComplete : function(ed, value, startValue){
62721 this.editing = false;
62722 this.activeEditor = null;
62723 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
62725 var field = this.colModel.getDataIndex(ed.col);
62730 originalValue: startValue,
62737 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
62740 if(String(value) !== String(startValue)){
62742 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
62743 r.set(field, e.value);
62744 // if we are dealing with a combo box..
62745 // then we also set the 'name' colum to be the displayField
62746 if (ed.field.displayField && ed.field.name) {
62747 r.set(ed.field.name, ed.field.el.dom.value);
62750 delete e.cancel; //?? why!!!
62751 this.fireEvent("afteredit", e);
62754 this.fireEvent("afteredit", e); // always fire it!
62756 this.view.focusCell(ed.row, ed.col);
62760 * Starts editing the specified for the specified row/column
62761 * @param {Number} rowIndex
62762 * @param {Number} colIndex
62764 startEditing : function(row, col){
62765 this.stopEditing();
62766 if(this.colModel.isCellEditable(col, row)){
62767 this.view.ensureVisible(row, col, true);
62769 var r = this.dataSource.getAt(row);
62770 var field = this.colModel.getDataIndex(col);
62771 var cell = Roo.get(this.view.getCell(row,col));
62776 value: r.data[field],
62781 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
62782 this.editing = true;
62783 var ed = this.colModel.getCellEditor(col, row);
62789 ed.render(ed.parentEl || document.body);
62795 (function(){ // complex but required for focus issues in safari, ie and opera
62799 ed.on("complete", this.onEditComplete, this, {single: true});
62800 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
62801 this.activeEditor = ed;
62802 var v = r.data[field];
62803 ed.startEdit(this.view.getCell(row, col), v);
62804 // combo's with 'displayField and name set
62805 if (ed.field.displayField && ed.field.name) {
62806 ed.field.el.dom.value = r.data[ed.field.name];
62810 }).defer(50, this);
62816 * Stops any active editing
62818 stopEditing : function(){
62819 if(this.activeEditor){
62820 this.activeEditor.completeEdit();
62822 this.activeEditor = null;
62826 * Called to get grid's drag proxy text, by default returns this.ddText.
62829 getDragDropText : function(){
62830 var count = this.selModel.getSelectedCell() ? 1 : 0;
62831 return String.format(this.ddText, count, count == 1 ? '' : 's');
62836 * Ext JS Library 1.1.1
62837 * Copyright(c) 2006-2007, Ext JS, LLC.
62839 * Originally Released Under LGPL - original licence link has changed is not relivant.
62842 * <script type="text/javascript">
62845 // private - not really -- you end up using it !
62846 // This is a support class used internally by the Grid components
62849 * @class Roo.grid.GridEditor
62850 * @extends Roo.Editor
62851 * Class for creating and editable grid elements.
62852 * @param {Object} config any settings (must include field)
62854 Roo.grid.GridEditor = function(field, config){
62855 if (!config && field.field) {
62857 field = Roo.factory(config.field, Roo.form);
62859 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
62860 field.monitorTab = false;
62863 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
62866 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
62869 alignment: "tl-tl",
62872 cls: "x-small-editor x-grid-editor",
62877 * Ext JS Library 1.1.1
62878 * Copyright(c) 2006-2007, Ext JS, LLC.
62880 * Originally Released Under LGPL - original licence link has changed is not relivant.
62883 * <script type="text/javascript">
62888 Roo.grid.PropertyRecord = Roo.data.Record.create([
62889 {name:'name',type:'string'}, 'value'
62893 Roo.grid.PropertyStore = function(grid, source){
62895 this.store = new Roo.data.Store({
62896 recordType : Roo.grid.PropertyRecord
62898 this.store.on('update', this.onUpdate, this);
62900 this.setSource(source);
62902 Roo.grid.PropertyStore.superclass.constructor.call(this);
62907 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
62908 setSource : function(o){
62910 this.store.removeAll();
62913 if(this.isEditableValue(o[k])){
62914 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
62917 this.store.loadRecords({records: data}, {}, true);
62920 onUpdate : function(ds, record, type){
62921 if(type == Roo.data.Record.EDIT){
62922 var v = record.data['value'];
62923 var oldValue = record.modified['value'];
62924 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
62925 this.source[record.id] = v;
62927 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
62934 getProperty : function(row){
62935 return this.store.getAt(row);
62938 isEditableValue: function(val){
62939 if(val && val instanceof Date){
62941 }else if(typeof val == 'object' || typeof val == 'function'){
62947 setValue : function(prop, value){
62948 this.source[prop] = value;
62949 this.store.getById(prop).set('value', value);
62952 getSource : function(){
62953 return this.source;
62957 Roo.grid.PropertyColumnModel = function(grid, store){
62960 g.PropertyColumnModel.superclass.constructor.call(this, [
62961 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
62962 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
62964 this.store = store;
62965 this.bselect = Roo.DomHelper.append(document.body, {
62966 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
62967 {tag: 'option', value: 'true', html: 'true'},
62968 {tag: 'option', value: 'false', html: 'false'}
62971 Roo.id(this.bselect);
62974 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
62975 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
62976 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
62977 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
62978 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
62980 this.renderCellDelegate = this.renderCell.createDelegate(this);
62981 this.renderPropDelegate = this.renderProp.createDelegate(this);
62984 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
62988 valueText : 'Value',
62990 dateFormat : 'm/j/Y',
62993 renderDate : function(dateVal){
62994 return dateVal.dateFormat(this.dateFormat);
62997 renderBool : function(bVal){
62998 return bVal ? 'true' : 'false';
63001 isCellEditable : function(colIndex, rowIndex){
63002 return colIndex == 1;
63005 getRenderer : function(col){
63007 this.renderCellDelegate : this.renderPropDelegate;
63010 renderProp : function(v){
63011 return this.getPropertyName(v);
63014 renderCell : function(val){
63016 if(val instanceof Date){
63017 rv = this.renderDate(val);
63018 }else if(typeof val == 'boolean'){
63019 rv = this.renderBool(val);
63021 return Roo.util.Format.htmlEncode(rv);
63024 getPropertyName : function(name){
63025 var pn = this.grid.propertyNames;
63026 return pn && pn[name] ? pn[name] : name;
63029 getCellEditor : function(colIndex, rowIndex){
63030 var p = this.store.getProperty(rowIndex);
63031 var n = p.data['name'], val = p.data['value'];
63033 if(typeof(this.grid.customEditors[n]) == 'string'){
63034 return this.editors[this.grid.customEditors[n]];
63036 if(typeof(this.grid.customEditors[n]) != 'undefined'){
63037 return this.grid.customEditors[n];
63039 if(val instanceof Date){
63040 return this.editors['date'];
63041 }else if(typeof val == 'number'){
63042 return this.editors['number'];
63043 }else if(typeof val == 'boolean'){
63044 return this.editors['boolean'];
63046 return this.editors['string'];
63052 * @class Roo.grid.PropertyGrid
63053 * @extends Roo.grid.EditorGrid
63054 * This class represents the interface of a component based property grid control.
63055 * <br><br>Usage:<pre><code>
63056 var grid = new Roo.grid.PropertyGrid("my-container-id", {
63064 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
63065 * The container MUST have some type of size defined for the grid to fill. The container will be
63066 * automatically set to position relative if it isn't already.
63067 * @param {Object} config A config object that sets properties on this grid.
63069 Roo.grid.PropertyGrid = function(container, config){
63070 config = config || {};
63071 var store = new Roo.grid.PropertyStore(this);
63072 this.store = store;
63073 var cm = new Roo.grid.PropertyColumnModel(this, store);
63074 store.store.sort('name', 'ASC');
63075 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
63078 enableColLock:false,
63079 enableColumnMove:false,
63081 trackMouseOver: false,
63084 this.getGridEl().addClass('x-props-grid');
63085 this.lastEditRow = null;
63086 this.on('columnresize', this.onColumnResize, this);
63089 * @event beforepropertychange
63090 * Fires before a property changes (return false to stop?)
63091 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
63092 * @param {String} id Record Id
63093 * @param {String} newval New Value
63094 * @param {String} oldval Old Value
63096 "beforepropertychange": true,
63098 * @event propertychange
63099 * Fires after a property changes
63100 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
63101 * @param {String} id Record Id
63102 * @param {String} newval New Value
63103 * @param {String} oldval Old Value
63105 "propertychange": true
63107 this.customEditors = this.customEditors || {};
63109 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
63112 * @cfg {Object} customEditors map of colnames=> custom editors.
63113 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
63114 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
63115 * false disables editing of the field.
63119 * @cfg {Object} propertyNames map of property Names to their displayed value
63122 render : function(){
63123 Roo.grid.PropertyGrid.superclass.render.call(this);
63124 this.autoSize.defer(100, this);
63127 autoSize : function(){
63128 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
63130 this.view.fitColumns();
63134 onColumnResize : function(){
63135 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
63139 * Sets the data for the Grid
63140 * accepts a Key => Value object of all the elements avaiable.
63141 * @param {Object} data to appear in grid.
63143 setSource : function(source){
63144 this.store.setSource(source);
63148 * Gets all the data from the grid.
63149 * @return {Object} data data stored in grid
63151 getSource : function(){
63152 return this.store.getSource();
63161 * @class Roo.grid.Calendar
63162 * @extends Roo.util.Grid
63163 * This class extends the Grid to provide a calendar widget
63164 * <br><br>Usage:<pre><code>
63165 var grid = new Roo.grid.Calendar("my-container-id", {
63168 selModel: mySelectionModel,
63169 autoSizeColumns: true,
63170 monitorWindowResize: false,
63171 trackMouseOver: true
63172 eventstore : real data store..
63178 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
63179 * The container MUST have some type of size defined for the grid to fill. The container will be
63180 * automatically set to position relative if it isn't already.
63181 * @param {Object} config A config object that sets properties on this grid.
63183 Roo.grid.Calendar = function(container, config){
63184 // initialize the container
63185 this.container = Roo.get(container);
63186 this.container.update("");
63187 this.container.setStyle("overflow", "hidden");
63188 this.container.addClass('x-grid-container');
63190 this.id = this.container.id;
63192 Roo.apply(this, config);
63193 // check and correct shorthanded configs
63197 for (var r = 0;r < 6;r++) {
63200 for (var c =0;c < 7;c++) {
63204 if (this.eventStore) {
63205 this.eventStore= Roo.factory(this.eventStore, Roo.data);
63206 this.eventStore.on('load',this.onLoad, this);
63207 this.eventStore.on('beforeload',this.clearEvents, this);
63211 this.dataSource = new Roo.data.Store({
63212 proxy: new Roo.data.MemoryProxy(rows),
63213 reader: new Roo.data.ArrayReader({}, [
63214 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
63217 this.dataSource.load();
63218 this.ds = this.dataSource;
63219 this.ds.xmodule = this.xmodule || false;
63222 var cellRender = function(v,x,r)
63224 return String.format(
63225 '<div class="fc-day fc-widget-content"><div>' +
63226 '<div class="fc-event-container"></div>' +
63227 '<div class="fc-day-number">{0}</div>'+
63229 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
63230 '</div></div>', v);
63235 this.colModel = new Roo.grid.ColumnModel( [
63237 xtype: 'ColumnModel',
63239 dataIndex : 'weekday0',
63241 renderer : cellRender
63244 xtype: 'ColumnModel',
63246 dataIndex : 'weekday1',
63248 renderer : cellRender
63251 xtype: 'ColumnModel',
63253 dataIndex : 'weekday2',
63254 header : 'Tuesday',
63255 renderer : cellRender
63258 xtype: 'ColumnModel',
63260 dataIndex : 'weekday3',
63261 header : 'Wednesday',
63262 renderer : cellRender
63265 xtype: 'ColumnModel',
63267 dataIndex : 'weekday4',
63268 header : 'Thursday',
63269 renderer : cellRender
63272 xtype: 'ColumnModel',
63274 dataIndex : 'weekday5',
63276 renderer : cellRender
63279 xtype: 'ColumnModel',
63281 dataIndex : 'weekday6',
63282 header : 'Saturday',
63283 renderer : cellRender
63286 this.cm = this.colModel;
63287 this.cm.xmodule = this.xmodule || false;
63291 //this.selModel = new Roo.grid.CellSelectionModel();
63292 //this.sm = this.selModel;
63293 //this.selModel.init(this);
63297 this.container.setWidth(this.width);
63301 this.container.setHeight(this.height);
63308 * The raw click event for the entire grid.
63309 * @param {Roo.EventObject} e
63314 * The raw dblclick event for the entire grid.
63315 * @param {Roo.EventObject} e
63319 * @event contextmenu
63320 * The raw contextmenu event for the entire grid.
63321 * @param {Roo.EventObject} e
63323 "contextmenu" : true,
63326 * The raw mousedown event for the entire grid.
63327 * @param {Roo.EventObject} e
63329 "mousedown" : true,
63332 * The raw mouseup event for the entire grid.
63333 * @param {Roo.EventObject} e
63338 * The raw mouseover event for the entire grid.
63339 * @param {Roo.EventObject} e
63341 "mouseover" : true,
63344 * The raw mouseout event for the entire grid.
63345 * @param {Roo.EventObject} e
63350 * The raw keypress event for the entire grid.
63351 * @param {Roo.EventObject} e
63356 * The raw keydown event for the entire grid.
63357 * @param {Roo.EventObject} e
63365 * Fires when a cell is clicked
63366 * @param {Grid} this
63367 * @param {Number} rowIndex
63368 * @param {Number} columnIndex
63369 * @param {Roo.EventObject} e
63371 "cellclick" : true,
63373 * @event celldblclick
63374 * Fires when a cell is double clicked
63375 * @param {Grid} this
63376 * @param {Number} rowIndex
63377 * @param {Number} columnIndex
63378 * @param {Roo.EventObject} e
63380 "celldblclick" : true,
63383 * Fires when a row is clicked
63384 * @param {Grid} this
63385 * @param {Number} rowIndex
63386 * @param {Roo.EventObject} e
63390 * @event rowdblclick
63391 * Fires when a row is double clicked
63392 * @param {Grid} this
63393 * @param {Number} rowIndex
63394 * @param {Roo.EventObject} e
63396 "rowdblclick" : true,
63398 * @event headerclick
63399 * Fires when a header is clicked
63400 * @param {Grid} this
63401 * @param {Number} columnIndex
63402 * @param {Roo.EventObject} e
63404 "headerclick" : true,
63406 * @event headerdblclick
63407 * Fires when a header cell is double clicked
63408 * @param {Grid} this
63409 * @param {Number} columnIndex
63410 * @param {Roo.EventObject} e
63412 "headerdblclick" : true,
63414 * @event rowcontextmenu
63415 * Fires when a row is right clicked
63416 * @param {Grid} this
63417 * @param {Number} rowIndex
63418 * @param {Roo.EventObject} e
63420 "rowcontextmenu" : true,
63422 * @event cellcontextmenu
63423 * Fires when a cell is right clicked
63424 * @param {Grid} this
63425 * @param {Number} rowIndex
63426 * @param {Number} cellIndex
63427 * @param {Roo.EventObject} e
63429 "cellcontextmenu" : true,
63431 * @event headercontextmenu
63432 * Fires when a header is right clicked
63433 * @param {Grid} this
63434 * @param {Number} columnIndex
63435 * @param {Roo.EventObject} e
63437 "headercontextmenu" : true,
63439 * @event bodyscroll
63440 * Fires when the body element is scrolled
63441 * @param {Number} scrollLeft
63442 * @param {Number} scrollTop
63444 "bodyscroll" : true,
63446 * @event columnresize
63447 * Fires when the user resizes a column
63448 * @param {Number} columnIndex
63449 * @param {Number} newSize
63451 "columnresize" : true,
63453 * @event columnmove
63454 * Fires when the user moves a column
63455 * @param {Number} oldIndex
63456 * @param {Number} newIndex
63458 "columnmove" : true,
63461 * Fires when row(s) start being dragged
63462 * @param {Grid} this
63463 * @param {Roo.GridDD} dd The drag drop object
63464 * @param {event} e The raw browser event
63466 "startdrag" : true,
63469 * Fires when a drag operation is complete
63470 * @param {Grid} this
63471 * @param {Roo.GridDD} dd The drag drop object
63472 * @param {event} e The raw browser event
63477 * Fires when dragged row(s) are dropped on a valid DD target
63478 * @param {Grid} this
63479 * @param {Roo.GridDD} dd The drag drop object
63480 * @param {String} targetId The target drag drop object
63481 * @param {event} e The raw browser event
63486 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
63487 * @param {Grid} this
63488 * @param {Roo.GridDD} dd The drag drop object
63489 * @param {String} targetId The target drag drop object
63490 * @param {event} e The raw browser event
63495 * Fires when the dragged row(s) first cross another DD target while being dragged
63496 * @param {Grid} this
63497 * @param {Roo.GridDD} dd The drag drop object
63498 * @param {String} targetId The target drag drop object
63499 * @param {event} e The raw browser event
63501 "dragenter" : true,
63504 * Fires when the dragged row(s) leave another DD target while being dragged
63505 * @param {Grid} this
63506 * @param {Roo.GridDD} dd The drag drop object
63507 * @param {String} targetId The target drag drop object
63508 * @param {event} e The raw browser event
63513 * Fires when a row is rendered, so you can change add a style to it.
63514 * @param {GridView} gridview The grid view
63515 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
63521 * Fires when the grid is rendered
63522 * @param {Grid} grid
63527 * Fires when a date is selected
63528 * @param {DatePicker} this
63529 * @param {Date} date The selected date
63533 * @event monthchange
63534 * Fires when the displayed month changes
63535 * @param {DatePicker} this
63536 * @param {Date} date The selected month
63538 'monthchange': true,
63540 * @event evententer
63541 * Fires when mouse over an event
63542 * @param {Calendar} this
63543 * @param {event} Event
63545 'evententer': true,
63547 * @event eventleave
63548 * Fires when the mouse leaves an
63549 * @param {Calendar} this
63552 'eventleave': true,
63554 * @event eventclick
63555 * Fires when the mouse click an
63556 * @param {Calendar} this
63559 'eventclick': true,
63561 * @event eventrender
63562 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
63563 * @param {Calendar} this
63564 * @param {data} data to be modified
63566 'eventrender': true
63570 Roo.grid.Grid.superclass.constructor.call(this);
63571 this.on('render', function() {
63572 this.view.el.addClass('x-grid-cal');
63574 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
63578 if (!Roo.grid.Calendar.style) {
63579 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
63582 '.x-grid-cal .x-grid-col' : {
63583 height: 'auto !important',
63584 'vertical-align': 'top'
63586 '.x-grid-cal .fc-event-hori' : {
63597 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
63599 * @cfg {Store} eventStore The store that loads events.
63604 activeDate : false,
63607 monitorWindowResize : false,
63610 resizeColumns : function() {
63611 var col = (this.view.el.getWidth() / 7) - 3;
63612 // loop through cols, and setWidth
63613 for(var i =0 ; i < 7 ; i++){
63614 this.cm.setColumnWidth(i, col);
63617 setDate :function(date) {
63619 Roo.log('setDate?');
63621 this.resizeColumns();
63622 var vd = this.activeDate;
63623 this.activeDate = date;
63624 // if(vd && this.el){
63625 // var t = date.getTime();
63626 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
63627 // Roo.log('using add remove');
63629 // this.fireEvent('monthchange', this, date);
63631 // this.cells.removeClass("fc-state-highlight");
63632 // this.cells.each(function(c){
63633 // if(c.dateValue == t){
63634 // c.addClass("fc-state-highlight");
63635 // setTimeout(function(){
63636 // try{c.dom.firstChild.focus();}catch(e){}
63646 var days = date.getDaysInMonth();
63648 var firstOfMonth = date.getFirstDateOfMonth();
63649 var startingPos = firstOfMonth.getDay()-this.startDay;
63651 if(startingPos < this.startDay){
63655 var pm = date.add(Date.MONTH, -1);
63656 var prevStart = pm.getDaysInMonth()-startingPos;
63660 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
63662 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
63663 //this.cells.addClassOnOver('fc-state-hover');
63665 var cells = this.cells.elements;
63666 var textEls = this.textNodes;
63668 //Roo.each(cells, function(cell){
63669 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
63672 days += startingPos;
63674 // convert everything to numbers so it's fast
63675 var day = 86400000;
63676 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
63679 //Roo.log(prevStart);
63681 var today = new Date().clearTime().getTime();
63682 var sel = date.clearTime().getTime();
63683 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
63684 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
63685 var ddMatch = this.disabledDatesRE;
63686 var ddText = this.disabledDatesText;
63687 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
63688 var ddaysText = this.disabledDaysText;
63689 var format = this.format;
63691 var setCellClass = function(cal, cell){
63693 //Roo.log('set Cell Class');
63695 var t = d.getTime();
63700 cell.dateValue = t;
63702 cell.className += " fc-today";
63703 cell.className += " fc-state-highlight";
63704 cell.title = cal.todayText;
63707 // disable highlight in other month..
63708 cell.className += " fc-state-highlight";
63713 //cell.className = " fc-state-disabled";
63714 cell.title = cal.minText;
63718 //cell.className = " fc-state-disabled";
63719 cell.title = cal.maxText;
63723 if(ddays.indexOf(d.getDay()) != -1){
63724 // cell.title = ddaysText;
63725 // cell.className = " fc-state-disabled";
63728 if(ddMatch && format){
63729 var fvalue = d.dateFormat(format);
63730 if(ddMatch.test(fvalue)){
63731 cell.title = ddText.replace("%0", fvalue);
63732 cell.className = " fc-state-disabled";
63736 if (!cell.initialClassName) {
63737 cell.initialClassName = cell.dom.className;
63740 cell.dom.className = cell.initialClassName + ' ' + cell.className;
63745 for(; i < startingPos; i++) {
63746 cells[i].dayName = (++prevStart);
63747 Roo.log(textEls[i]);
63748 d.setDate(d.getDate()+1);
63750 //cells[i].className = "fc-past fc-other-month";
63751 setCellClass(this, cells[i]);
63756 for(; i < days; i++){
63757 intDay = i - startingPos + 1;
63758 cells[i].dayName = (intDay);
63759 d.setDate(d.getDate()+1);
63761 cells[i].className = ''; // "x-date-active";
63762 setCellClass(this, cells[i]);
63766 for(; i < 42; i++) {
63767 //textEls[i].innerHTML = (++extraDays);
63769 d.setDate(d.getDate()+1);
63770 cells[i].dayName = (++extraDays);
63771 cells[i].className = "fc-future fc-other-month";
63772 setCellClass(this, cells[i]);
63775 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
63777 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
63779 // this will cause all the cells to mis
63782 for (var r = 0;r < 6;r++) {
63783 for (var c =0;c < 7;c++) {
63784 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
63788 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
63789 for(i=0;i<cells.length;i++) {
63791 this.cells.elements[i].dayName = cells[i].dayName ;
63792 this.cells.elements[i].className = cells[i].className;
63793 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
63794 this.cells.elements[i].title = cells[i].title ;
63795 this.cells.elements[i].dateValue = cells[i].dateValue ;
63801 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
63802 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
63804 ////if(totalRows != 6){
63805 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
63806 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
63809 this.fireEvent('monthchange', this, date);
63814 * Returns the grid's SelectionModel.
63815 * @return {SelectionModel}
63817 getSelectionModel : function(){
63818 if(!this.selModel){
63819 this.selModel = new Roo.grid.CellSelectionModel();
63821 return this.selModel;
63825 this.eventStore.load()
63831 findCell : function(dt) {
63832 dt = dt.clearTime().getTime();
63834 this.cells.each(function(c){
63835 //Roo.log("check " +c.dateValue + '?=' + dt);
63836 if(c.dateValue == dt){
63846 findCells : function(rec) {
63847 var s = rec.data.start_dt.clone().clearTime().getTime();
63849 var e= rec.data.end_dt.clone().clearTime().getTime();
63852 this.cells.each(function(c){
63853 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
63855 if(c.dateValue > e){
63858 if(c.dateValue < s){
63867 findBestRow: function(cells)
63871 for (var i =0 ; i < cells.length;i++) {
63872 ret = Math.max(cells[i].rows || 0,ret);
63879 addItem : function(rec)
63881 // look for vertical location slot in
63882 var cells = this.findCells(rec);
63884 rec.row = this.findBestRow(cells);
63886 // work out the location.
63890 for(var i =0; i < cells.length; i++) {
63898 if (crow.start.getY() == cells[i].getY()) {
63900 crow.end = cells[i];
63916 for (var i = 0; i < cells.length;i++) {
63917 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
63924 clearEvents: function() {
63926 if (!this.eventStore.getCount()) {
63929 // reset number of rows in cells.
63930 Roo.each(this.cells.elements, function(c){
63934 this.eventStore.each(function(e) {
63935 this.clearEvent(e);
63940 clearEvent : function(ev)
63943 Roo.each(ev.els, function(el) {
63944 el.un('mouseenter' ,this.onEventEnter, this);
63945 el.un('mouseleave' ,this.onEventLeave, this);
63953 renderEvent : function(ev,ctr) {
63955 ctr = this.view.el.select('.fc-event-container',true).first();
63959 this.clearEvent(ev);
63965 var cells = ev.cells;
63966 var rows = ev.rows;
63967 this.fireEvent('eventrender', this, ev);
63969 for(var i =0; i < rows.length; i++) {
63973 cls += ' fc-event-start';
63975 if ((i+1) == rows.length) {
63976 cls += ' fc-event-end';
63979 //Roo.log(ev.data);
63980 // how many rows should it span..
63981 var cg = this.eventTmpl.append(ctr,Roo.apply({
63984 }, ev.data) , true);
63987 cg.on('mouseenter' ,this.onEventEnter, this, ev);
63988 cg.on('mouseleave' ,this.onEventLeave, this, ev);
63989 cg.on('click', this.onEventClick, this, ev);
63993 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
63994 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
63997 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
63998 cg.setWidth(ebox.right - sbox.x -2);
64002 renderEvents: function()
64004 // first make sure there is enough space..
64006 if (!this.eventTmpl) {
64007 this.eventTmpl = new Roo.Template(
64008 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
64009 '<div class="fc-event-inner">' +
64010 '<span class="fc-event-time">{time}</span>' +
64011 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
64013 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
64021 this.cells.each(function(c) {
64022 //Roo.log(c.select('.fc-day-content div',true).first());
64023 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
64026 var ctr = this.view.el.select('.fc-event-container',true).first();
64029 this.eventStore.each(function(ev){
64031 this.renderEvent(ev);
64035 this.view.layout();
64039 onEventEnter: function (e, el,event,d) {
64040 this.fireEvent('evententer', this, el, event);
64043 onEventLeave: function (e, el,event,d) {
64044 this.fireEvent('eventleave', this, el, event);
64047 onEventClick: function (e, el,event,d) {
64048 this.fireEvent('eventclick', this, el, event);
64051 onMonthChange: function () {
64055 onLoad: function () {
64057 //Roo.log('calendar onload');
64059 if(this.eventStore.getCount() > 0){
64063 this.eventStore.each(function(d){
64068 if (typeof(add.end_dt) == 'undefined') {
64069 Roo.log("Missing End time in calendar data: ");
64073 if (typeof(add.start_dt) == 'undefined') {
64074 Roo.log("Missing Start time in calendar data: ");
64078 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
64079 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
64080 add.id = add.id || d.id;
64081 add.title = add.title || '??';
64089 this.renderEvents();
64099 render : function ()
64103 if (!this.view.el.hasClass('course-timesheet')) {
64104 this.view.el.addClass('course-timesheet');
64106 if (this.tsStyle) {
64111 Roo.log(_this.grid.view.el.getWidth());
64114 this.tsStyle = Roo.util.CSS.createStyleSheet({
64115 '.course-timesheet .x-grid-row' : {
64118 '.x-grid-row td' : {
64119 'vertical-align' : 0
64121 '.course-edit-link' : {
64123 'text-overflow' : 'ellipsis',
64124 'overflow' : 'hidden',
64125 'white-space' : 'nowrap',
64126 'cursor' : 'pointer'
64131 '.de-act-sup-link' : {
64132 'color' : 'purple',
64133 'text-decoration' : 'line-through'
64137 'text-decoration' : 'line-through'
64139 '.course-timesheet .course-highlight' : {
64140 'border-top-style': 'dashed !important',
64141 'border-bottom-bottom': 'dashed !important'
64143 '.course-timesheet .course-item' : {
64144 'font-family' : 'tahoma, arial, helvetica',
64145 'font-size' : '11px',
64146 'overflow' : 'hidden',
64147 'padding-left' : '10px',
64148 'padding-right' : '10px',
64149 'padding-top' : '10px'
64157 monitorWindowResize : false,
64158 cellrenderer : function(v,x,r)
64163 xtype: 'CellSelectionModel',
64170 beforeload : function (_self, options)
64172 options.params = options.params || {};
64173 options.params._month = _this.monthField.getValue();
64174 options.params.limit = 9999;
64175 options.params['sort'] = 'when_dt';
64176 options.params['dir'] = 'ASC';
64177 this.proxy.loadResponse = this.loadResponse;
64179 //this.addColumns();
64181 load : function (_self, records, options)
64183 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
64184 // if you click on the translation.. you can edit it...
64185 var el = Roo.get(this);
64186 var id = el.dom.getAttribute('data-id');
64187 var d = el.dom.getAttribute('data-date');
64188 var t = el.dom.getAttribute('data-time');
64189 //var id = this.child('span').dom.textContent;
64192 Pman.Dialog.CourseCalendar.show({
64196 productitem_active : id ? 1 : 0
64198 _this.grid.ds.load({});
64203 _this.panel.fireEvent('resize', [ '', '' ]);
64206 loadResponse : function(o, success, response){
64207 // this is overridden on before load..
64209 Roo.log("our code?");
64210 //Roo.log(success);
64211 //Roo.log(response)
64212 delete this.activeRequest;
64214 this.fireEvent("loadexception", this, o, response);
64215 o.request.callback.call(o.request.scope, null, o.request.arg, false);
64220 result = o.reader.read(response);
64222 Roo.log("load exception?");
64223 this.fireEvent("loadexception", this, o, response, e);
64224 o.request.callback.call(o.request.scope, null, o.request.arg, false);
64227 Roo.log("ready...");
64228 // loop through result.records;
64229 // and set this.tdate[date] = [] << array of records..
64231 Roo.each(result.records, function(r){
64233 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
64234 _this.tdata[r.data.when_dt.format('j')] = [];
64236 _this.tdata[r.data.when_dt.format('j')].push(r.data);
64239 //Roo.log(_this.tdata);
64241 result.records = [];
64242 result.totalRecords = 6;
64244 // let's generate some duumy records for the rows.
64245 //var st = _this.dateField.getValue();
64247 // work out monday..
64248 //st = st.add(Date.DAY, -1 * st.format('w'));
64250 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
64252 var firstOfMonth = date.getFirstDayOfMonth();
64253 var days = date.getDaysInMonth();
64255 var firstAdded = false;
64256 for (var i = 0; i < result.totalRecords ; i++) {
64257 //var d= st.add(Date.DAY, i);
64260 for(var w = 0 ; w < 7 ; w++){
64261 if(!firstAdded && firstOfMonth != w){
64268 var dd = (d > 0 && d < 10) ? "0"+d : d;
64269 row['weekday'+w] = String.format(
64270 '<span style="font-size: 16px;"><b>{0}</b></span>'+
64271 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
64273 date.format('Y-m-')+dd
64276 if(typeof(_this.tdata[d]) != 'undefined'){
64277 Roo.each(_this.tdata[d], function(r){
64281 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
64282 if(r.parent_id*1>0){
64283 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
64286 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
64287 deactive = 'de-act-link';
64290 row['weekday'+w] += String.format(
64291 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
64293 r.product_id_name, //1
64294 r.when_dt.format('h:ia'), //2
64304 // only do this if something added..
64306 result.records.push(_this.grid.dataSource.reader.newRow(row));
64310 // push it twice. (second one with an hour..
64314 this.fireEvent("load", this, o, o.request.arg);
64315 o.request.callback.call(o.request.scope, result, o.request.arg, true);
64317 sortInfo : {field: 'when_dt', direction : 'ASC' },
64319 xtype: 'HttpProxy',
64322 url : baseURL + '/Roo/Shop_course.php'
64325 xtype: 'JsonReader',
64342 'name': 'parent_id',
64346 'name': 'product_id',
64350 'name': 'productitem_id',
64368 click : function (_self, e)
64370 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
64371 sd.setMonth(sd.getMonth()-1);
64372 _this.monthField.setValue(sd.format('Y-m-d'));
64373 _this.grid.ds.load({});
64379 xtype: 'Separator',
64383 xtype: 'MonthField',
64386 render : function (_self)
64388 _this.monthField = _self;
64389 // _this.monthField.set today
64391 select : function (combo, date)
64393 _this.grid.ds.load({});
64396 value : (function() { return new Date(); })()
64399 xtype: 'Separator',
64405 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
64415 click : function (_self, e)
64417 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
64418 sd.setMonth(sd.getMonth()+1);
64419 _this.monthField.setValue(sd.format('Y-m-d'));
64420 _this.grid.ds.load({});
64433 * Ext JS Library 1.1.1
64434 * Copyright(c) 2006-2007, Ext JS, LLC.
64436 * Originally Released Under LGPL - original licence link has changed is not relivant.
64439 * <script type="text/javascript">
64443 * @class Roo.LoadMask
64444 * A simple utility class for generically masking elements while loading data. If the element being masked has
64445 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
64446 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
64447 * element's UpdateManager load indicator and will be destroyed after the initial load.
64449 * Create a new LoadMask
64450 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
64451 * @param {Object} config The config object
64453 Roo.LoadMask = function(el, config){
64454 this.el = Roo.get(el);
64455 Roo.apply(this, config);
64457 this.store.on('beforeload', this.onBeforeLoad, this);
64458 this.store.on('load', this.onLoad, this);
64459 this.store.on('loadexception', this.onLoadException, this);
64460 this.removeMask = false;
64462 var um = this.el.getUpdateManager();
64463 um.showLoadIndicator = false; // disable the default indicator
64464 um.on('beforeupdate', this.onBeforeLoad, this);
64465 um.on('update', this.onLoad, this);
64466 um.on('failure', this.onLoad, this);
64467 this.removeMask = true;
64471 Roo.LoadMask.prototype = {
64473 * @cfg {Boolean} removeMask
64474 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
64475 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
64478 * @cfg {String} msg
64479 * The text to display in a centered loading message box (defaults to 'Loading...')
64481 msg : 'Loading...',
64483 * @cfg {String} msgCls
64484 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
64486 msgCls : 'x-mask-loading',
64489 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
64495 * Disables the mask to prevent it from being displayed
64497 disable : function(){
64498 this.disabled = true;
64502 * Enables the mask so that it can be displayed
64504 enable : function(){
64505 this.disabled = false;
64508 onLoadException : function()
64510 Roo.log(arguments);
64512 if (typeof(arguments[3]) != 'undefined') {
64513 Roo.MessageBox.alert("Error loading",arguments[3]);
64517 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
64518 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
64527 this.el.unmask(this.removeMask);
64530 onLoad : function()
64532 this.el.unmask(this.removeMask);
64536 onBeforeLoad : function(){
64537 if(!this.disabled){
64538 this.el.mask(this.msg, this.msgCls);
64543 destroy : function(){
64545 this.store.un('beforeload', this.onBeforeLoad, this);
64546 this.store.un('load', this.onLoad, this);
64547 this.store.un('loadexception', this.onLoadException, this);
64549 var um = this.el.getUpdateManager();
64550 um.un('beforeupdate', this.onBeforeLoad, this);
64551 um.un('update', this.onLoad, this);
64552 um.un('failure', this.onLoad, this);
64557 * Ext JS Library 1.1.1
64558 * Copyright(c) 2006-2007, Ext JS, LLC.
64560 * Originally Released Under LGPL - original licence link has changed is not relivant.
64563 * <script type="text/javascript">
64568 * @class Roo.XTemplate
64569 * @extends Roo.Template
64570 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
64572 var t = new Roo.XTemplate(
64573 '<select name="{name}">',
64574 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
64578 // then append, applying the master template values
64581 * Supported features:
64586 {a_variable} - output encoded.
64587 {a_variable.format:("Y-m-d")} - call a method on the variable
64588 {a_variable:raw} - unencoded output
64589 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
64590 {a_variable:this.method_on_template(...)} - call a method on the template object.
64595 <tpl for="a_variable or condition.."></tpl>
64596 <tpl if="a_variable or condition"></tpl>
64597 <tpl exec="some javascript"></tpl>
64598 <tpl name="named_template"></tpl> (experimental)
64600 <tpl for="."></tpl> - just iterate the property..
64601 <tpl for=".."></tpl> - iterates with the parent (probably the template)
64605 Roo.XTemplate = function()
64607 Roo.XTemplate.superclass.constructor.apply(this, arguments);
64614 Roo.extend(Roo.XTemplate, Roo.Template, {
64617 * The various sub templates
64622 * basic tag replacing syntax
64625 * // you can fake an object call by doing this
64629 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
64632 * compile the template
64634 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
64637 compile: function()
64641 s = ['<tpl>', s, '</tpl>'].join('');
64643 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
64644 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
64645 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
64646 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
64647 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
64652 while(true == !!(m = s.match(re))){
64653 var forMatch = m[0].match(nameRe),
64654 ifMatch = m[0].match(ifRe),
64655 execMatch = m[0].match(execRe),
64656 namedMatch = m[0].match(namedRe),
64661 name = forMatch && forMatch[1] ? forMatch[1] : '';
64664 // if - puts fn into test..
64665 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
64667 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
64672 // exec - calls a function... returns empty if true is returned.
64673 exp = execMatch && execMatch[1] ? execMatch[1] : null;
64675 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
64683 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
64684 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
64685 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
64688 var uid = namedMatch ? namedMatch[1] : id;
64692 id: namedMatch ? namedMatch[1] : id,
64699 s = s.replace(m[0], '');
64701 s = s.replace(m[0], '{xtpl'+ id + '}');
64706 for(var i = tpls.length-1; i >= 0; --i){
64707 this.compileTpl(tpls[i]);
64708 this.tpls[tpls[i].id] = tpls[i];
64710 this.master = tpls[tpls.length-1];
64714 * same as applyTemplate, except it's done to one of the subTemplates
64715 * when using named templates, you can do:
64717 * var str = pl.applySubTemplate('your-name', values);
64720 * @param {Number} id of the template
64721 * @param {Object} values to apply to template
64722 * @param {Object} parent (normaly the instance of this object)
64724 applySubTemplate : function(id, values, parent)
64728 var t = this.tpls[id];
64732 if(t.test && !t.test.call(this, values, parent)){
64736 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
64737 Roo.log(e.toString());
64743 if(t.exec && t.exec.call(this, values, parent)){
64747 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
64748 Roo.log(e.toString());
64753 var vs = t.target ? t.target.call(this, values, parent) : values;
64754 parent = t.target ? values : parent;
64755 if(t.target && vs instanceof Array){
64757 for(var i = 0, len = vs.length; i < len; i++){
64758 buf[buf.length] = t.compiled.call(this, vs[i], parent);
64760 return buf.join('');
64762 return t.compiled.call(this, vs, parent);
64764 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
64765 Roo.log(e.toString());
64766 Roo.log(t.compiled);
64771 compileTpl : function(tpl)
64773 var fm = Roo.util.Format;
64774 var useF = this.disableFormats !== true;
64775 var sep = Roo.isGecko ? "+" : ",";
64776 var undef = function(str) {
64777 Roo.log("Property not found :" + str);
64781 var fn = function(m, name, format, args)
64783 //Roo.log(arguments);
64784 args = args ? args.replace(/\\'/g,"'") : args;
64785 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
64786 if (typeof(format) == 'undefined') {
64787 format= 'htmlEncode';
64789 if (format == 'raw' ) {
64793 if(name.substr(0, 4) == 'xtpl'){
64794 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
64797 // build an array of options to determine if value is undefined..
64799 // basically get 'xxxx.yyyy' then do
64800 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
64801 // (function () { Roo.log("Property not found"); return ''; })() :
64806 Roo.each(name.split('.'), function(st) {
64807 lookfor += (lookfor.length ? '.': '') + st;
64808 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
64811 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
64814 if(format && useF){
64816 args = args ? ',' + args : "";
64818 if(format.substr(0, 5) != "this."){
64819 format = "fm." + format + '(';
64821 format = 'this.call("'+ format.substr(5) + '", ';
64825 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
64829 // called with xxyx.yuu:(test,test)
64831 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
64833 // raw.. - :raw modifier..
64834 return "'"+ sep + udef_st + name + ")"+sep+"'";
64838 // branched to use + in gecko and [].join() in others
64840 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
64841 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
64844 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
64845 body.push(tpl.body.replace(/(\r\n|\n)/g,
64846 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
64847 body.push("'].join('');};};");
64848 body = body.join('');
64851 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
64853 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
64859 applyTemplate : function(values){
64860 return this.master.compiled.call(this, values, {});
64861 //var s = this.subs;
64864 apply : function(){
64865 return this.applyTemplate.apply(this, arguments);
64870 Roo.XTemplate.from = function(el){
64871 el = Roo.getDom(el);
64872 return new Roo.XTemplate(el.value || el.innerHTML);