4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
673 * Find the current bootstrap width Grid size
674 * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675 * @returns {String} (xs|sm|md|lg|xl)
678 getGridSize : function()
680 var w = Roo.lib.Dom.getViewWidth();
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
705 "Roo.bootstrap.dash");
708 * Ext JS Library 1.1.1
709 * Copyright(c) 2006-2007, Ext JS, LLC.
711 * Originally Released Under LGPL - original licence link has changed is not relivant.
714 * <script type="text/javascript">
718 // wrappedn so fnCleanup is not in global scope...
720 function fnCleanUp() {
721 var p = Function.prototype;
722 delete p.createSequence;
724 delete p.createDelegate;
725 delete p.createCallback;
726 delete p.createInterceptor;
728 window.detachEvent("onunload", fnCleanUp);
730 window.attachEvent("onunload", fnCleanUp);
737 * These functions are available on every Function object (any JavaScript function).
739 Roo.apply(Function.prototype, {
741 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
742 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
743 * Will create a function that is bound to those 2 args.
744 * @return {Function} The new function
746 createCallback : function(/*args...*/){
747 // make args available, in function below
748 var args = arguments;
751 return method.apply(window, args);
756 * Creates a delegate (callback) that sets the scope to obj.
757 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
758 * Will create a function that is automatically scoped to this.
759 * @param {Object} obj (optional) The object for which the scope is set
760 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
761 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
762 * if a number the args are inserted at the specified position
763 * @return {Function} The new function
765 createDelegate : function(obj, args, appendArgs){
768 var callArgs = args || arguments;
769 if(appendArgs === true){
770 callArgs = Array.prototype.slice.call(arguments, 0);
771 callArgs = callArgs.concat(args);
772 }else if(typeof appendArgs == "number"){
773 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
774 var applyArgs = [appendArgs, 0].concat(args); // create method call params
775 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
777 return method.apply(obj || window, callArgs);
782 * Calls this function after the number of millseconds specified.
783 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
784 * @param {Object} obj (optional) The object for which the scope is set
785 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
786 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
787 * if a number the args are inserted at the specified position
788 * @return {Number} The timeout id that can be used with clearTimeout
790 defer : function(millis, obj, args, appendArgs){
791 var fn = this.createDelegate(obj, args, appendArgs);
793 return setTimeout(fn, millis);
799 * Create a combined function call sequence of the original function + the passed function.
800 * The resulting function returns the results of the original function.
801 * The passed fcn is called with the parameters of the original function
802 * @param {Function} fcn The function to sequence
803 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
804 * @return {Function} The new function
806 createSequence : function(fcn, scope){
807 if(typeof fcn != "function"){
812 var retval = method.apply(this || window, arguments);
813 fcn.apply(scope || this || window, arguments);
819 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
820 * The resulting function returns the results of the original function.
821 * The passed fcn is called with the parameters of the original function.
823 * @param {Function} fcn The function to call before the original
824 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
825 * @return {Function} The new function
827 createInterceptor : function(fcn, scope){
828 if(typeof fcn != "function"){
835 if(fcn.apply(scope || this || window, arguments) === false){
838 return method.apply(this || window, arguments);
844 * Ext JS Library 1.1.1
845 * Copyright(c) 2006-2007, Ext JS, LLC.
847 * Originally Released Under LGPL - original licence link has changed is not relivant.
850 * <script type="text/javascript">
853 Roo.applyIf(String, {
858 * Escapes the passed string for ' and \
859 * @param {String} string The string to escape
860 * @return {String} The escaped string
863 escape : function(string) {
864 return string.replace(/('|\\)/g, "\\$1");
868 * Pads the left side of a string with a specified character. This is especially useful
869 * for normalizing number and date strings. Example usage:
871 var s = String.leftPad('123', 5, '0');
872 // s now contains the string: '00123'
874 * @param {String} string The original string
875 * @param {Number} size The total length of the output string
876 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
877 * @return {String} The padded string
880 leftPad : function (val, size, ch) {
881 var result = new String(val);
882 if(ch === null || ch === undefined || ch === '') {
885 while (result.length < size) {
886 result = ch + result;
892 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
893 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
895 var cls = 'my-class', text = 'Some text';
896 var s = String.format('<div class="{0}">{1}</div>', cls, text);
897 // s now contains the string: '<div class="my-class">Some text</div>'
899 * @param {String} string The tokenized string to be formatted
900 * @param {String} value1 The value to replace token {0}
901 * @param {String} value2 Etc...
902 * @return {String} The formatted string
905 format : function(format){
906 var args = Array.prototype.slice.call(arguments, 1);
907 return format.replace(/\{(\d+)\}/g, function(m, i){
908 return Roo.util.Format.htmlEncode(args[i]);
916 * Utility function that allows you to easily switch a string between two alternating values. The passed value
917 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
918 * they are already different, the first value passed in is returned. Note that this method returns the new value
919 * but does not change the current string.
921 // alternate sort directions
922 sort = sort.toggle('ASC', 'DESC');
924 // instead of conditional logic:
925 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
927 * @param {String} value The value to compare to the current string
928 * @param {String} other The new value to use if the string already equals the first value passed in
929 * @return {String} The new value
932 String.prototype.toggle = function(value, other){
933 return this == value ? other : value;
938 * Remove invalid unicode characters from a string
940 * @return {String} The clean string
942 String.prototype.unicodeClean = function () {
943 return this.replace(/[\s\S]/g,
944 function(character) {
945 if (character.charCodeAt()< 256) {
949 encodeURIComponent(character);
960 * Ext JS Library 1.1.1
961 * Copyright(c) 2006-2007, Ext JS, LLC.
963 * Originally Released Under LGPL - original licence link has changed is not relivant.
966 * <script type="text/javascript">
972 Roo.applyIf(Number.prototype, {
974 * Checks whether or not the current number is within a desired range. If the number is already within the
975 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
976 * exceeded. Note that this method returns the constrained value but does not change the current number.
977 * @param {Number} min The minimum number in the range
978 * @param {Number} max The maximum number in the range
979 * @return {Number} The constrained value if outside the range, otherwise the current value
981 constrain : function(min, max){
982 return Math.min(Math.max(this, min), max);
986 * Ext JS Library 1.1.1
987 * Copyright(c) 2006-2007, Ext JS, LLC.
989 * Originally Released Under LGPL - original licence link has changed is not relivant.
992 * <script type="text/javascript">
997 Roo.applyIf(Array.prototype, {
1000 * Checks whether or not the specified object exists in the array.
1001 * @param {Object} o The object to check for
1002 * @return {Number} The index of o in the array (or -1 if it is not found)
1004 indexOf : function(o){
1005 for (var i = 0, len = this.length; i < len; i++){
1006 if(this[i] == o) { return i; }
1012 * Removes the specified object from the array. If the object is not found nothing happens.
1013 * @param {Object} o The object to remove
1015 remove : function(o){
1016 var index = this.indexOf(o);
1018 this.splice(index, 1);
1022 * Map (JS 1.6 compatibility)
1023 * @param {Function} function to call
1025 map : function(fun )
1027 var len = this.length >>> 0;
1028 if (typeof fun != "function") {
1029 throw new TypeError();
1031 var res = new Array(len);
1032 var thisp = arguments[1];
1033 for (var i = 0; i < len; i++)
1036 res[i] = fun.call(thisp, this[i], i, this);
1044 * @param {Array} o The array to compare to
1045 * @returns {Boolean} true if the same
1047 equals : function(b)
1049 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1056 if (this.length !== b.length) {
1060 // sort?? a.sort().equals(b.sort());
1062 for (var i = 0; i < this.length; ++i) {
1063 if (this[i] !== b[i]) {
1075 * Ext JS Library 1.1.1
1076 * Copyright(c) 2006-2007, Ext JS, LLC.
1078 * Originally Released Under LGPL - original licence link has changed is not relivant.
1081 * <script type="text/javascript">
1087 * The date parsing and format syntax is a subset of
1088 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1089 * supported will provide results equivalent to their PHP versions.
1091 * Following is the list of all currently supported formats:
1094 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1096 Format Output Description
1097 ------ ---------- --------------------------------------------------------------
1098 d 10 Day of the month, 2 digits with leading zeros
1099 D Wed A textual representation of a day, three letters
1100 j 10 Day of the month without leading zeros
1101 l Wednesday A full textual representation of the day of the week
1102 S th English ordinal day of month suffix, 2 chars (use with j)
1103 w 3 Numeric representation of the day of the week
1104 z 9 The julian date, or day of the year (0-365)
1105 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1106 F January A full textual representation of the month
1107 m 01 Numeric representation of a month, with leading zeros
1108 M Jan Month name abbreviation, three letters
1109 n 1 Numeric representation of a month, without leading zeros
1110 t 31 Number of days in the given month
1111 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1112 Y 2007 A full numeric representation of a year, 4 digits
1113 y 07 A two digit representation of a year
1114 a pm Lowercase Ante meridiem and Post meridiem
1115 A PM Uppercase Ante meridiem and Post meridiem
1116 g 3 12-hour format of an hour without leading zeros
1117 G 15 24-hour format of an hour without leading zeros
1118 h 03 12-hour format of an hour with leading zeros
1119 H 15 24-hour format of an hour with leading zeros
1120 i 05 Minutes with leading zeros
1121 s 01 Seconds, with leading zeros
1122 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1123 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1124 T CST Timezone setting of the machine running the code
1125 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1128 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1130 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1131 document.write(dt.format('Y-m-d')); //2007-01-10
1132 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1133 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
1136 * Here are some standard date/time patterns that you might find helpful. They
1137 * are not part of the source of Date.js, but to use them you can simply copy this
1138 * block of code into any script that is included after Date.js and they will also become
1139 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1142 ISO8601Long:"Y-m-d H:i:s",
1143 ISO8601Short:"Y-m-d",
1145 LongDate: "l, F d, Y",
1146 FullDateTime: "l, F d, Y g:i:s A",
1149 LongTime: "g:i:s A",
1150 SortableDateTime: "Y-m-d\\TH:i:s",
1151 UniversalSortableDateTime: "Y-m-d H:i:sO",
1158 var dt = new Date();
1159 document.write(dt.format(Date.patterns.ShortDate));
1164 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1165 * They generate precompiled functions from date formats instead of parsing and
1166 * processing the pattern every time you format a date. These functions are available
1167 * on every Date object (any javascript function).
1169 * The original article and download are here:
1170 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1177 Returns the number of milliseconds between this date and date
1178 @param {Date} date (optional) Defaults to now
1179 @return {Number} The diff in milliseconds
1180 @member Date getElapsed
1182 Date.prototype.getElapsed = function(date) {
1183 return Math.abs((date || new Date()).getTime()-this.getTime());
1185 // was in date file..
1189 Date.parseFunctions = {count:0};
1191 Date.parseRegexes = [];
1193 Date.formatFunctions = {count:0};
1196 Date.prototype.dateFormat = function(format) {
1197 if (Date.formatFunctions[format] == null) {
1198 Date.createNewFormat(format);
1200 var func = Date.formatFunctions[format];
1201 return this[func]();
1206 * Formats a date given the supplied format string
1207 * @param {String} format The format string
1208 * @return {String} The formatted date
1211 Date.prototype.format = Date.prototype.dateFormat;
1214 Date.createNewFormat = function(format) {
1215 var funcName = "format" + Date.formatFunctions.count++;
1216 Date.formatFunctions[format] = funcName;
1217 var code = "Date.prototype." + funcName + " = function(){return ";
1218 var special = false;
1220 for (var i = 0; i < format.length; ++i) {
1221 ch = format.charAt(i);
1222 if (!special && ch == "\\") {
1227 code += "'" + String.escape(ch) + "' + ";
1230 code += Date.getFormatCode(ch);
1233 /** eval:var:zzzzzzzzzzzzz */
1234 eval(code.substring(0, code.length - 3) + ";}");
1238 Date.getFormatCode = function(character) {
1239 switch (character) {
1241 return "String.leftPad(this.getDate(), 2, '0') + ";
1243 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1245 return "this.getDate() + ";
1247 return "Date.dayNames[this.getDay()] + ";
1249 return "this.getSuffix() + ";
1251 return "this.getDay() + ";
1253 return "this.getDayOfYear() + ";
1255 return "this.getWeekOfYear() + ";
1257 return "Date.monthNames[this.getMonth()] + ";
1259 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1261 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1263 return "(this.getMonth() + 1) + ";
1265 return "this.getDaysInMonth() + ";
1267 return "(this.isLeapYear() ? 1 : 0) + ";
1269 return "this.getFullYear() + ";
1271 return "('' + this.getFullYear()).substring(2, 4) + ";
1273 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1275 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1277 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1279 return "this.getHours() + ";
1281 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1283 return "String.leftPad(this.getHours(), 2, '0') + ";
1285 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1287 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1289 return "this.getGMTOffset() + ";
1291 return "this.getGMTColonOffset() + ";
1293 return "this.getTimezone() + ";
1295 return "(this.getTimezoneOffset() * -60) + ";
1297 return "'" + String.escape(character) + "' + ";
1302 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1303 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1304 * the date format that is not specified will default to the current date value for that part. Time parts can also
1305 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1306 * string or the parse operation will fail.
1309 //dt = Fri May 25 2007 (current date)
1310 var dt = new Date();
1312 //dt = Thu May 25 2006 (today's month/day in 2006)
1313 dt = Date.parseDate("2006", "Y");
1315 //dt = Sun Jan 15 2006 (all date parts specified)
1316 dt = Date.parseDate("2006-1-15", "Y-m-d");
1318 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1319 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1321 * @param {String} input The unparsed date as a string
1322 * @param {String} format The format the date is in
1323 * @return {Date} The parsed date
1326 Date.parseDate = function(input, format) {
1327 if (Date.parseFunctions[format] == null) {
1328 Date.createParser(format);
1330 var func = Date.parseFunctions[format];
1331 return Date[func](input);
1337 Date.createParser = function(format) {
1338 var funcName = "parse" + Date.parseFunctions.count++;
1339 var regexNum = Date.parseRegexes.length;
1340 var currentGroup = 1;
1341 Date.parseFunctions[format] = funcName;
1343 var code = "Date." + funcName + " = function(input){\n"
1344 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1345 + "var d = new Date();\n"
1346 + "y = d.getFullYear();\n"
1347 + "m = d.getMonth();\n"
1348 + "d = d.getDate();\n"
1349 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1350 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1351 + "if (results && results.length > 0) {";
1354 var special = false;
1356 for (var i = 0; i < format.length; ++i) {
1357 ch = format.charAt(i);
1358 if (!special && ch == "\\") {
1363 regex += String.escape(ch);
1366 var obj = Date.formatCodeToRegex(ch, currentGroup);
1367 currentGroup += obj.g;
1369 if (obj.g && obj.c) {
1375 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1376 + "{v = new Date(y, m, d, h, i, s);}\n"
1377 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1378 + "{v = new Date(y, m, d, h, i);}\n"
1379 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1380 + "{v = new Date(y, m, d, h);}\n"
1381 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1382 + "{v = new Date(y, m, d);}\n"
1383 + "else if (y >= 0 && m >= 0)\n"
1384 + "{v = new Date(y, m);}\n"
1385 + "else if (y >= 0)\n"
1386 + "{v = new Date(y);}\n"
1387 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1388 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1389 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1392 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1393 /** eval:var:zzzzzzzzzzzzz */
1398 Date.formatCodeToRegex = function(character, currentGroup) {
1399 switch (character) {
1403 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1406 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1407 s:"(\\d{1,2})"}; // day of month without leading zeroes
1410 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1411 s:"(\\d{2})"}; // day of month with leading zeroes
1415 s:"(?:" + Date.dayNames.join("|") + ")"};
1419 s:"(?:st|nd|rd|th)"};
1434 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1435 s:"(" + Date.monthNames.join("|") + ")"};
1438 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1439 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1442 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1443 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1446 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1447 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1458 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1462 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1463 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1467 c:"if (results[" + currentGroup + "] == 'am') {\n"
1468 + "if (h == 12) { h = 0; }\n"
1469 + "} else { if (h < 12) { h += 12; }}",
1473 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1474 + "if (h == 12) { h = 0; }\n"
1475 + "} else { if (h < 12) { h += 12; }}",
1480 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1481 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1485 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1486 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1489 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1493 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1498 "o = results[", currentGroup, "];\n",
1499 "var sn = o.substring(0,1);\n", // get + / - sign
1500 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1501 "var mn = o.substring(3,5) % 60;\n", // get minutes
1502 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1503 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1505 s:"([+\-]\\d{2,4})"};
1511 "o = results[", currentGroup, "];\n",
1512 "var sn = o.substring(0,1);\n",
1513 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1514 "var mn = o.substring(4,6) % 60;\n",
1515 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1516 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1522 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1525 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1526 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1527 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1531 s:String.escape(character)};
1536 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1537 * @return {String} The abbreviated timezone name (e.g. 'CST')
1539 Date.prototype.getTimezone = function() {
1540 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1544 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1545 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1547 Date.prototype.getGMTOffset = function() {
1548 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1549 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1550 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1554 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1555 * @return {String} 2-characters representing hours and 2-characters representing minutes
1556 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1558 Date.prototype.getGMTColonOffset = function() {
1559 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1560 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1562 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1566 * Get the numeric day number of the year, adjusted for leap year.
1567 * @return {Number} 0 through 364 (365 in leap years)
1569 Date.prototype.getDayOfYear = function() {
1571 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1572 for (var i = 0; i < this.getMonth(); ++i) {
1573 num += Date.daysInMonth[i];
1575 return num + this.getDate() - 1;
1579 * Get the string representation of the numeric week number of the year
1580 * (equivalent to the format specifier 'W').
1581 * @return {String} '00' through '52'
1583 Date.prototype.getWeekOfYear = function() {
1584 // Skip to Thursday of this week
1585 var now = this.getDayOfYear() + (4 - this.getDay());
1586 // Find the first Thursday of the year
1587 var jan1 = new Date(this.getFullYear(), 0, 1);
1588 var then = (7 - jan1.getDay() + 4);
1589 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1593 * Whether or not the current date is in a leap year.
1594 * @return {Boolean} True if the current date is in a leap year, else false
1596 Date.prototype.isLeapYear = function() {
1597 var year = this.getFullYear();
1598 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1602 * Get the first day of the current month, adjusted for leap year. The returned value
1603 * is the numeric day index within the week (0-6) which can be used in conjunction with
1604 * the {@link #monthNames} array to retrieve the textual day name.
1607 var dt = new Date('1/10/2007');
1608 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1610 * @return {Number} The day number (0-6)
1612 Date.prototype.getFirstDayOfMonth = function() {
1613 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1614 return (day < 0) ? (day + 7) : day;
1618 * Get the last day of the current month, adjusted for leap year. The returned value
1619 * is the numeric day index within the week (0-6) which can be used in conjunction with
1620 * the {@link #monthNames} array to retrieve the textual day name.
1623 var dt = new Date('1/10/2007');
1624 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1626 * @return {Number} The day number (0-6)
1628 Date.prototype.getLastDayOfMonth = function() {
1629 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1630 return (day < 0) ? (day + 7) : day;
1635 * Get the first date of this date's month
1638 Date.prototype.getFirstDateOfMonth = function() {
1639 return new Date(this.getFullYear(), this.getMonth(), 1);
1643 * Get the last date of this date's month
1646 Date.prototype.getLastDateOfMonth = function() {
1647 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1650 * Get the number of days in the current month, adjusted for leap year.
1651 * @return {Number} The number of days in the month
1653 Date.prototype.getDaysInMonth = function() {
1654 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1655 return Date.daysInMonth[this.getMonth()];
1659 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1660 * @return {String} 'st, 'nd', 'rd' or 'th'
1662 Date.prototype.getSuffix = function() {
1663 switch (this.getDate()) {
1680 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1683 * An array of textual month names.
1684 * Override these values for international dates, for example...
1685 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1704 * An array of textual day names.
1705 * Override these values for international dates, for example...
1706 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1722 Date.monthNumbers = {
1737 * Creates and returns a new Date instance with the exact same date value as the called instance.
1738 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1739 * variable will also be changed. When the intention is to create a new variable that will not
1740 * modify the original instance, you should create a clone.
1742 * Example of correctly cloning a date:
1745 var orig = new Date('10/1/2006');
1748 document.write(orig); //returns 'Thu Oct 05 2006'!
1751 var orig = new Date('10/1/2006');
1752 var copy = orig.clone();
1754 document.write(orig); //returns 'Thu Oct 01 2006'
1756 * @return {Date} The new Date instance
1758 Date.prototype.clone = function() {
1759 return new Date(this.getTime());
1763 * Clears any time information from this date
1764 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1765 @return {Date} this or the clone
1767 Date.prototype.clearTime = function(clone){
1769 return this.clone().clearTime();
1774 this.setMilliseconds(0);
1779 // safari setMonth is broken -- check that this is only donw once...
1780 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1781 Date.brokenSetMonth = Date.prototype.setMonth;
1782 Date.prototype.setMonth = function(num){
1784 var n = Math.ceil(-num);
1785 var back_year = Math.ceil(n/12);
1786 var month = (n % 12) ? 12 - n % 12 : 0 ;
1787 this.setFullYear(this.getFullYear() - back_year);
1788 return Date.brokenSetMonth.call(this, month);
1790 return Date.brokenSetMonth.apply(this, arguments);
1795 /** Date interval constant
1799 /** Date interval constant
1803 /** Date interval constant
1807 /** Date interval constant
1811 /** Date interval constant
1815 /** Date interval constant
1819 /** Date interval constant
1825 * Provides a convenient method of performing basic date arithmetic. This method
1826 * does not modify the Date instance being called - it creates and returns
1827 * a new Date instance containing the resulting date value.
1832 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1833 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1835 //Negative values will subtract correctly:
1836 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1837 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1839 //You can even chain several calls together in one line!
1840 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1841 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1844 * @param {String} interval A valid date interval enum value
1845 * @param {Number} value The amount to add to the current date
1846 * @return {Date} The new Date instance
1848 Date.prototype.add = function(interval, value){
1849 var d = this.clone();
1850 if (!interval || value === 0) { return d; }
1851 switch(interval.toLowerCase()){
1853 d.setMilliseconds(this.getMilliseconds() + value);
1856 d.setSeconds(this.getSeconds() + value);
1859 d.setMinutes(this.getMinutes() + value);
1862 d.setHours(this.getHours() + value);
1865 d.setDate(this.getDate() + value);
1868 var day = this.getDate();
1870 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1873 d.setMonth(this.getMonth() + value);
1876 d.setFullYear(this.getFullYear() + value);
1882 * @class Roo.lib.Dom
1886 * Dom utils (from YIU afaik)
1892 * Get the view width
1893 * @param {Boolean} full True will get the full document, otherwise it's the view width
1894 * @return {Number} The width
1897 getViewWidth : function(full) {
1898 return full ? this.getDocumentWidth() : this.getViewportWidth();
1901 * Get the view height
1902 * @param {Boolean} full True will get the full document, otherwise it's the view height
1903 * @return {Number} The height
1905 getViewHeight : function(full) {
1906 return full ? this.getDocumentHeight() : this.getViewportHeight();
1909 * Get the Full Document height
1910 * @return {Number} The height
1912 getDocumentHeight: function() {
1913 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1914 return Math.max(scrollHeight, this.getViewportHeight());
1917 * Get the Full Document width
1918 * @return {Number} The width
1920 getDocumentWidth: function() {
1921 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1922 return Math.max(scrollWidth, this.getViewportWidth());
1925 * Get the Window Viewport height
1926 * @return {Number} The height
1928 getViewportHeight: function() {
1929 var height = self.innerHeight;
1930 var mode = document.compatMode;
1932 if ((mode || Roo.isIE) && !Roo.isOpera) {
1933 height = (mode == "CSS1Compat") ?
1934 document.documentElement.clientHeight :
1935 document.body.clientHeight;
1941 * Get the Window Viewport width
1942 * @return {Number} The width
1944 getViewportWidth: function() {
1945 var width = self.innerWidth;
1946 var mode = document.compatMode;
1948 if (mode || Roo.isIE) {
1949 width = (mode == "CSS1Compat") ?
1950 document.documentElement.clientWidth :
1951 document.body.clientWidth;
1956 isAncestor : function(p, c) {
1963 if (p.contains && !Roo.isSafari) {
1964 return p.contains(c);
1965 } else if (p.compareDocumentPosition) {
1966 return !!(p.compareDocumentPosition(c) & 16);
1968 var parent = c.parentNode;
1973 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1976 parent = parent.parentNode;
1982 getRegion : function(el) {
1983 return Roo.lib.Region.getRegion(el);
1986 getY : function(el) {
1987 return this.getXY(el)[1];
1990 getX : function(el) {
1991 return this.getXY(el)[0];
1994 getXY : function(el) {
1995 var p, pe, b, scroll, bd = document.body;
1996 el = Roo.getDom(el);
1997 var fly = Roo.lib.AnimBase.fly;
1998 if (el.getBoundingClientRect) {
1999 b = el.getBoundingClientRect();
2000 scroll = fly(document).getScroll();
2001 return [b.left + scroll.left, b.top + scroll.top];
2007 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2014 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2021 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2022 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2029 if (p != el && pe.getStyle('overflow') != 'visible') {
2037 if (Roo.isSafari && hasAbsolute) {
2042 if (Roo.isGecko && !hasAbsolute) {
2044 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2045 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2049 while (p && p != bd) {
2050 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2062 setXY : function(el, xy) {
2063 el = Roo.fly(el, '_setXY');
2065 var pts = el.translatePoints(xy);
2066 if (xy[0] !== false) {
2067 el.dom.style.left = pts.left + "px";
2069 if (xy[1] !== false) {
2070 el.dom.style.top = pts.top + "px";
2074 setX : function(el, x) {
2075 this.setXY(el, [x, false]);
2078 setY : function(el, y) {
2079 this.setXY(el, [false, y]);
2083 * Portions of this file are based on pieces of Yahoo User Interface Library
2084 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2085 * YUI licensed under the BSD License:
2086 * http://developer.yahoo.net/yui/license.txt
2087 * <script type="text/javascript">
2091 Roo.lib.Event = function() {
2092 var loadComplete = false;
2094 var unloadListeners = [];
2096 var onAvailStack = [];
2098 var lastError = null;
2111 startInterval: function() {
2112 if (!this._interval) {
2114 var callback = function() {
2115 self._tryPreloadAttach();
2117 this._interval = setInterval(callback, this.POLL_INTERVAL);
2122 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2123 onAvailStack.push({ id: p_id,
2126 override: p_override,
2127 checkReady: false });
2129 retryCount = this.POLL_RETRYS;
2130 this.startInterval();
2134 addListener: function(el, eventName, fn) {
2135 el = Roo.getDom(el);
2140 if ("unload" == eventName) {
2141 unloadListeners[unloadListeners.length] =
2142 [el, eventName, fn];
2146 var wrappedFn = function(e) {
2147 return fn(Roo.lib.Event.getEvent(e));
2150 var li = [el, eventName, fn, wrappedFn];
2152 var index = listeners.length;
2153 listeners[index] = li;
2155 this.doAdd(el, eventName, wrappedFn, false);
2161 removeListener: function(el, eventName, fn) {
2164 el = Roo.getDom(el);
2167 return this.purgeElement(el, false, eventName);
2171 if ("unload" == eventName) {
2173 for (i = 0,len = unloadListeners.length; i < len; i++) {
2174 var li = unloadListeners[i];
2177 li[1] == eventName &&
2179 unloadListeners.splice(i, 1);
2187 var cacheItem = null;
2190 var index = arguments[3];
2192 if ("undefined" == typeof index) {
2193 index = this._getCacheIndex(el, eventName, fn);
2197 cacheItem = listeners[index];
2200 if (!el || !cacheItem) {
2204 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2206 delete listeners[index][this.WFN];
2207 delete listeners[index][this.FN];
2208 listeners.splice(index, 1);
2215 getTarget: function(ev, resolveTextNode) {
2216 ev = ev.browserEvent || ev;
2217 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2218 var t = ev.target || ev.srcElement;
2219 return this.resolveTextNode(t);
2223 resolveTextNode: function(node) {
2224 if (Roo.isSafari && node && 3 == node.nodeType) {
2225 return node.parentNode;
2232 getPageX: function(ev) {
2233 ev = ev.browserEvent || ev;
2234 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2236 if (!x && 0 !== x) {
2237 x = ev.clientX || 0;
2240 x += this.getScroll()[1];
2248 getPageY: function(ev) {
2249 ev = ev.browserEvent || ev;
2250 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2252 if (!y && 0 !== y) {
2253 y = ev.clientY || 0;
2256 y += this.getScroll()[0];
2265 getXY: function(ev) {
2266 ev = ev.browserEvent || ev;
2267 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2268 return [this.getPageX(ev), this.getPageY(ev)];
2272 getRelatedTarget: function(ev) {
2273 ev = ev.browserEvent || ev;
2274 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2275 var t = ev.relatedTarget;
2277 if (ev.type == "mouseout") {
2279 } else if (ev.type == "mouseover") {
2284 return this.resolveTextNode(t);
2288 getTime: function(ev) {
2289 ev = ev.browserEvent || ev;
2290 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2292 var t = new Date().getTime();
2296 this.lastError = ex;
2305 stopEvent: function(ev) {
2306 this.stopPropagation(ev);
2307 this.preventDefault(ev);
2311 stopPropagation: function(ev) {
2312 ev = ev.browserEvent || ev;
2313 if (ev.stopPropagation) {
2314 ev.stopPropagation();
2316 ev.cancelBubble = true;
2321 preventDefault: function(ev) {
2322 ev = ev.browserEvent || ev;
2323 if(ev.preventDefault) {
2324 ev.preventDefault();
2326 ev.returnValue = false;
2331 getEvent: function(e) {
2332 var ev = e || window.event;
2334 var c = this.getEvent.caller;
2336 ev = c.arguments[0];
2337 if (ev && Event == ev.constructor) {
2347 getCharCode: function(ev) {
2348 ev = ev.browserEvent || ev;
2349 return ev.charCode || ev.keyCode || 0;
2353 _getCacheIndex: function(el, eventName, fn) {
2354 for (var i = 0,len = listeners.length; i < len; ++i) {
2355 var li = listeners[i];
2357 li[this.FN] == fn &&
2358 li[this.EL] == el &&
2359 li[this.TYPE] == eventName) {
2371 getEl: function(id) {
2372 return document.getElementById(id);
2376 clearCache: function() {
2380 _load: function(e) {
2381 loadComplete = true;
2382 var EU = Roo.lib.Event;
2386 EU.doRemove(window, "load", EU._load);
2391 _tryPreloadAttach: function() {
2400 var tryAgain = !loadComplete;
2402 tryAgain = (retryCount > 0);
2407 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2408 var item = onAvailStack[i];
2410 var el = this.getEl(item.id);
2413 if (!item.checkReady ||
2416 (document && document.body)) {
2419 if (item.override) {
2420 if (item.override === true) {
2423 scope = item.override;
2426 item.fn.call(scope, item.obj);
2427 onAvailStack[i] = null;
2430 notAvail.push(item);
2435 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2439 this.startInterval();
2441 clearInterval(this._interval);
2442 this._interval = null;
2445 this.locked = false;
2452 purgeElement: function(el, recurse, eventName) {
2453 var elListeners = this.getListeners(el, eventName);
2455 for (var i = 0,len = elListeners.length; i < len; ++i) {
2456 var l = elListeners[i];
2457 this.removeListener(el, l.type, l.fn);
2461 if (recurse && el && el.childNodes) {
2462 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2463 this.purgeElement(el.childNodes[i], recurse, eventName);
2469 getListeners: function(el, eventName) {
2470 var results = [], searchLists;
2472 searchLists = [listeners, unloadListeners];
2473 } else if (eventName == "unload") {
2474 searchLists = [unloadListeners];
2476 searchLists = [listeners];
2479 for (var j = 0; j < searchLists.length; ++j) {
2480 var searchList = searchLists[j];
2481 if (searchList && searchList.length > 0) {
2482 for (var i = 0,len = searchList.length; i < len; ++i) {
2483 var l = searchList[i];
2484 if (l && l[this.EL] === el &&
2485 (!eventName || eventName === l[this.TYPE])) {
2490 adjust: l[this.ADJ_SCOPE],
2498 return (results.length) ? results : null;
2502 _unload: function(e) {
2504 var EU = Roo.lib.Event, i, j, l, len, index;
2506 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2507 l = unloadListeners[i];
2510 if (l[EU.ADJ_SCOPE]) {
2511 if (l[EU.ADJ_SCOPE] === true) {
2514 scope = l[EU.ADJ_SCOPE];
2517 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2518 unloadListeners[i] = null;
2524 unloadListeners = null;
2526 if (listeners && listeners.length > 0) {
2527 j = listeners.length;
2530 l = listeners[index];
2532 EU.removeListener(l[EU.EL], l[EU.TYPE],
2542 EU.doRemove(window, "unload", EU._unload);
2547 getScroll: function() {
2548 var dd = document.documentElement, db = document.body;
2549 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2550 return [dd.scrollTop, dd.scrollLeft];
2552 return [db.scrollTop, db.scrollLeft];
2559 doAdd: function () {
2560 if (window.addEventListener) {
2561 return function(el, eventName, fn, capture) {
2562 el.addEventListener(eventName, fn, (capture));
2564 } else if (window.attachEvent) {
2565 return function(el, eventName, fn, capture) {
2566 el.attachEvent("on" + eventName, fn);
2575 doRemove: function() {
2576 if (window.removeEventListener) {
2577 return function (el, eventName, fn, capture) {
2578 el.removeEventListener(eventName, fn, (capture));
2580 } else if (window.detachEvent) {
2581 return function (el, eventName, fn) {
2582 el.detachEvent("on" + eventName, fn);
2594 var E = Roo.lib.Event;
2595 E.on = E.addListener;
2596 E.un = E.removeListener;
2598 if (document && document.body) {
2601 E.doAdd(window, "load", E._load);
2603 E.doAdd(window, "unload", E._unload);
2604 E._tryPreloadAttach();
2608 * Portions of this file are based on pieces of Yahoo User Interface Library
2609 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2610 * YUI licensed under the BSD License:
2611 * http://developer.yahoo.net/yui/license.txt
2612 * <script type="text/javascript">
2618 * @class Roo.lib.Ajax
2625 request : function(method, uri, cb, data, options) {
2627 var hs = options.headers;
2630 if(hs.hasOwnProperty(h)){
2631 this.initHeader(h, hs[h], false);
2635 if(options.xmlData){
2636 this.initHeader('Content-Type', 'text/xml', false);
2638 data = options.xmlData;
2642 return this.asyncRequest(method, uri, cb, data);
2645 serializeForm : function(form) {
2646 if(typeof form == 'string') {
2647 form = (document.getElementById(form) || document.forms[form]);
2650 var el, name, val, disabled, data = '', hasSubmit = false;
2651 for (var i = 0; i < form.elements.length; i++) {
2652 el = form.elements[i];
2653 disabled = form.elements[i].disabled;
2654 name = form.elements[i].name;
2655 val = form.elements[i].value;
2657 if (!disabled && name){
2661 case 'select-multiple':
2662 for (var j = 0; j < el.options.length; j++) {
2663 if (el.options[j].selected) {
2665 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2668 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2676 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2689 if(hasSubmit == false) {
2690 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2695 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2700 data = data.substr(0, data.length - 1);
2708 useDefaultHeader:true,
2710 defaultPostHeader:'application/x-www-form-urlencoded',
2712 useDefaultXhrHeader:true,
2714 defaultXhrHeader:'XMLHttpRequest',
2716 hasDefaultHeaders:true,
2728 setProgId:function(id)
2730 this.activeX.unshift(id);
2733 setDefaultPostHeader:function(b)
2735 this.useDefaultHeader = b;
2738 setDefaultXhrHeader:function(b)
2740 this.useDefaultXhrHeader = b;
2743 setPollingInterval:function(i)
2745 if (typeof i == 'number' && isFinite(i)) {
2746 this.pollInterval = i;
2750 createXhrObject:function(transactionId)
2756 http = new XMLHttpRequest();
2758 obj = { conn:http, tId:transactionId };
2762 for (var i = 0; i < this.activeX.length; ++i) {
2766 http = new ActiveXObject(this.activeX[i]);
2768 obj = { conn:http, tId:transactionId };
2781 getConnectionObject:function()
2784 var tId = this.transactionId;
2788 o = this.createXhrObject(tId);
2790 this.transactionId++;
2801 asyncRequest:function(method, uri, callback, postData)
2803 var o = this.getConnectionObject();
2809 o.conn.open(method, uri, true);
2811 if (this.useDefaultXhrHeader) {
2812 if (!this.defaultHeaders['X-Requested-With']) {
2813 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2817 if(postData && this.useDefaultHeader){
2818 this.initHeader('Content-Type', this.defaultPostHeader);
2821 if (this.hasDefaultHeaders || this.hasHeaders) {
2825 this.handleReadyState(o, callback);
2826 o.conn.send(postData || null);
2832 handleReadyState:function(o, callback)
2836 if (callback && callback.timeout) {
2838 this.timeout[o.tId] = window.setTimeout(function() {
2839 oConn.abort(o, callback, true);
2840 }, callback.timeout);
2843 this.poll[o.tId] = window.setInterval(
2845 if (o.conn && o.conn.readyState == 4) {
2846 window.clearInterval(oConn.poll[o.tId]);
2847 delete oConn.poll[o.tId];
2849 if(callback && callback.timeout) {
2850 window.clearTimeout(oConn.timeout[o.tId]);
2851 delete oConn.timeout[o.tId];
2854 oConn.handleTransactionResponse(o, callback);
2857 , this.pollInterval);
2860 handleTransactionResponse:function(o, callback, isAbort)
2864 this.releaseObject(o);
2868 var httpStatus, responseObject;
2872 if (o.conn.status !== undefined && o.conn.status != 0) {
2873 httpStatus = o.conn.status;
2885 if (httpStatus >= 200 && httpStatus < 300) {
2886 responseObject = this.createResponseObject(o, callback.argument);
2887 if (callback.success) {
2888 if (!callback.scope) {
2889 callback.success(responseObject);
2894 callback.success.apply(callback.scope, [responseObject]);
2899 switch (httpStatus) {
2907 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2908 if (callback.failure) {
2909 if (!callback.scope) {
2910 callback.failure(responseObject);
2913 callback.failure.apply(callback.scope, [responseObject]);
2918 responseObject = this.createResponseObject(o, callback.argument);
2919 if (callback.failure) {
2920 if (!callback.scope) {
2921 callback.failure(responseObject);
2924 callback.failure.apply(callback.scope, [responseObject]);
2930 this.releaseObject(o);
2931 responseObject = null;
2934 createResponseObject:function(o, callbackArg)
2941 var headerStr = o.conn.getAllResponseHeaders();
2942 var header = headerStr.split('\n');
2943 for (var i = 0; i < header.length; i++) {
2944 var delimitPos = header[i].indexOf(':');
2945 if (delimitPos != -1) {
2946 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2954 obj.status = o.conn.status;
2955 obj.statusText = o.conn.statusText;
2956 obj.getResponseHeader = headerObj;
2957 obj.getAllResponseHeaders = headerStr;
2958 obj.responseText = o.conn.responseText;
2959 obj.responseXML = o.conn.responseXML;
2961 if (typeof callbackArg !== undefined) {
2962 obj.argument = callbackArg;
2968 createExceptionObject:function(tId, callbackArg, isAbort)
2971 var COMM_ERROR = 'communication failure';
2972 var ABORT_CODE = -1;
2973 var ABORT_ERROR = 'transaction aborted';
2979 obj.status = ABORT_CODE;
2980 obj.statusText = ABORT_ERROR;
2983 obj.status = COMM_CODE;
2984 obj.statusText = COMM_ERROR;
2988 obj.argument = callbackArg;
2994 initHeader:function(label, value, isDefault)
2996 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2998 if (headerObj[label] === undefined) {
2999 headerObj[label] = value;
3004 headerObj[label] = value + "," + headerObj[label];
3008 this.hasDefaultHeaders = true;
3011 this.hasHeaders = true;
3016 setHeader:function(o)
3018 if (this.hasDefaultHeaders) {
3019 for (var prop in this.defaultHeaders) {
3020 if (this.defaultHeaders.hasOwnProperty(prop)) {
3021 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3026 if (this.hasHeaders) {
3027 for (var prop in this.headers) {
3028 if (this.headers.hasOwnProperty(prop)) {
3029 o.conn.setRequestHeader(prop, this.headers[prop]);
3033 this.hasHeaders = false;
3037 resetDefaultHeaders:function() {
3038 delete this.defaultHeaders;
3039 this.defaultHeaders = {};
3040 this.hasDefaultHeaders = false;
3043 abort:function(o, callback, isTimeout)
3045 if(this.isCallInProgress(o)) {
3047 window.clearInterval(this.poll[o.tId]);
3048 delete this.poll[o.tId];
3050 delete this.timeout[o.tId];
3053 this.handleTransactionResponse(o, callback, true);
3063 isCallInProgress:function(o)
3066 return o.conn.readyState != 4 && o.conn.readyState != 0;
3075 releaseObject:function(o)
3084 'MSXML2.XMLHTTP.3.0',
3092 * Portions of this file are based on pieces of Yahoo User Interface Library
3093 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3094 * YUI licensed under the BSD License:
3095 * http://developer.yahoo.net/yui/license.txt
3096 * <script type="text/javascript">
3100 Roo.lib.Region = function(t, r, b, l) {
3110 Roo.lib.Region.prototype = {
3111 contains : function(region) {
3112 return ( region.left >= this.left &&
3113 region.right <= this.right &&
3114 region.top >= this.top &&
3115 region.bottom <= this.bottom );
3119 getArea : function() {
3120 return ( (this.bottom - this.top) * (this.right - this.left) );
3123 intersect : function(region) {
3124 var t = Math.max(this.top, region.top);
3125 var r = Math.min(this.right, region.right);
3126 var b = Math.min(this.bottom, region.bottom);
3127 var l = Math.max(this.left, region.left);
3129 if (b >= t && r >= l) {
3130 return new Roo.lib.Region(t, r, b, l);
3135 union : function(region) {
3136 var t = Math.min(this.top, region.top);
3137 var r = Math.max(this.right, region.right);
3138 var b = Math.max(this.bottom, region.bottom);
3139 var l = Math.min(this.left, region.left);
3141 return new Roo.lib.Region(t, r, b, l);
3144 adjust : function(t, l, b, r) {
3153 Roo.lib.Region.getRegion = function(el) {
3154 var p = Roo.lib.Dom.getXY(el);
3157 var r = p[0] + el.offsetWidth;
3158 var b = p[1] + el.offsetHeight;
3161 return new Roo.lib.Region(t, r, b, l);
3164 * Portions of this file are based on pieces of Yahoo User Interface Library
3165 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3166 * YUI licensed under the BSD License:
3167 * http://developer.yahoo.net/yui/license.txt
3168 * <script type="text/javascript">
3171 //@@dep Roo.lib.Region
3174 Roo.lib.Point = function(x, y) {
3175 if (x instanceof Array) {
3179 this.x = this.right = this.left = this[0] = x;
3180 this.y = this.top = this.bottom = this[1] = y;
3183 Roo.lib.Point.prototype = new Roo.lib.Region();
3185 * Portions of this file are based on pieces of Yahoo User Interface Library
3186 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3187 * YUI licensed under the BSD License:
3188 * http://developer.yahoo.net/yui/license.txt
3189 * <script type="text/javascript">
3196 scroll : function(el, args, duration, easing, cb, scope) {
3197 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3200 motion : function(el, args, duration, easing, cb, scope) {
3201 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3204 color : function(el, args, duration, easing, cb, scope) {
3205 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3208 run : function(el, args, duration, easing, cb, scope, type) {
3209 type = type || Roo.lib.AnimBase;
3210 if (typeof easing == "string") {
3211 easing = Roo.lib.Easing[easing];
3213 var anim = new type(el, args, duration, easing);
3214 anim.animateX(function() {
3215 Roo.callback(cb, scope);
3221 * Portions of this file are based on pieces of Yahoo User Interface Library
3222 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3223 * YUI licensed under the BSD License:
3224 * http://developer.yahoo.net/yui/license.txt
3225 * <script type="text/javascript">
3233 if (!libFlyweight) {
3234 libFlyweight = new Roo.Element.Flyweight();
3236 libFlyweight.dom = el;
3237 return libFlyweight;
3240 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3244 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3246 this.init(el, attributes, duration, method);
3250 Roo.lib.AnimBase.fly = fly;
3254 Roo.lib.AnimBase.prototype = {
3256 toString: function() {
3257 var el = this.getEl();
3258 var id = el.id || el.tagName;
3259 return ("Anim " + id);
3263 noNegatives: /width|height|opacity|padding/i,
3264 offsetAttribute: /^((width|height)|(top|left))$/,
3265 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3266 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3270 doMethod: function(attr, start, end) {
3271 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3275 setAttribute: function(attr, val, unit) {
3276 if (this.patterns.noNegatives.test(attr)) {
3277 val = (val > 0) ? val : 0;
3280 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3284 getAttribute: function(attr) {
3285 var el = this.getEl();
3286 var val = fly(el).getStyle(attr);
3288 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3289 return parseFloat(val);
3292 var a = this.patterns.offsetAttribute.exec(attr) || [];
3293 var pos = !!( a[3] );
3294 var box = !!( a[2] );
3297 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3298 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3307 getDefaultUnit: function(attr) {
3308 if (this.patterns.defaultUnit.test(attr)) {
3315 animateX : function(callback, scope) {
3316 var f = function() {
3317 this.onComplete.removeListener(f);
3318 if (typeof callback == "function") {
3319 callback.call(scope || this, this);
3322 this.onComplete.addListener(f, this);
3327 setRuntimeAttribute: function(attr) {
3330 var attributes = this.attributes;
3332 this.runtimeAttributes[attr] = {};
3334 var isset = function(prop) {
3335 return (typeof prop !== 'undefined');
3338 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3342 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3345 if (isset(attributes[attr]['to'])) {
3346 end = attributes[attr]['to'];
3347 } else if (isset(attributes[attr]['by'])) {
3348 if (start.constructor == Array) {
3350 for (var i = 0, len = start.length; i < len; ++i) {
3351 end[i] = start[i] + attributes[attr]['by'][i];
3354 end = start + attributes[attr]['by'];
3358 this.runtimeAttributes[attr].start = start;
3359 this.runtimeAttributes[attr].end = end;
3362 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3366 init: function(el, attributes, duration, method) {
3368 var isAnimated = false;
3371 var startTime = null;
3374 var actualFrames = 0;
3377 el = Roo.getDom(el);
3380 this.attributes = attributes || {};
3383 this.duration = duration || 1;
3386 this.method = method || Roo.lib.Easing.easeNone;
3389 this.useSeconds = true;
3392 this.currentFrame = 0;
3395 this.totalFrames = Roo.lib.AnimMgr.fps;
3398 this.getEl = function() {
3403 this.isAnimated = function() {
3408 this.getStartTime = function() {
3412 this.runtimeAttributes = {};
3415 this.animate = function() {
3416 if (this.isAnimated()) {
3420 this.currentFrame = 0;
3422 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3424 Roo.lib.AnimMgr.registerElement(this);
3428 this.stop = function(finish) {
3430 this.currentFrame = this.totalFrames;
3431 this._onTween.fire();
3433 Roo.lib.AnimMgr.stop(this);
3436 var onStart = function() {
3437 this.onStart.fire();
3439 this.runtimeAttributes = {};
3440 for (var attr in this.attributes) {
3441 this.setRuntimeAttribute(attr);
3446 startTime = new Date();
3450 var onTween = function() {
3452 duration: new Date() - this.getStartTime(),
3453 currentFrame: this.currentFrame
3456 data.toString = function() {
3458 'duration: ' + data.duration +
3459 ', currentFrame: ' + data.currentFrame
3463 this.onTween.fire(data);
3465 var runtimeAttributes = this.runtimeAttributes;
3467 for (var attr in runtimeAttributes) {
3468 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3474 var onComplete = function() {
3475 var actual_duration = (new Date() - startTime) / 1000 ;
3478 duration: actual_duration,
3479 frames: actualFrames,
3480 fps: actualFrames / actual_duration
3483 data.toString = function() {
3485 'duration: ' + data.duration +
3486 ', frames: ' + data.frames +
3487 ', fps: ' + data.fps
3493 this.onComplete.fire(data);
3497 this._onStart = new Roo.util.Event(this);
3498 this.onStart = new Roo.util.Event(this);
3499 this.onTween = new Roo.util.Event(this);
3500 this._onTween = new Roo.util.Event(this);
3501 this.onComplete = new Roo.util.Event(this);
3502 this._onComplete = new Roo.util.Event(this);
3503 this._onStart.addListener(onStart);
3504 this._onTween.addListener(onTween);
3505 this._onComplete.addListener(onComplete);
3510 * Portions of this file are based on pieces of Yahoo User Interface Library
3511 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3512 * YUI licensed under the BSD License:
3513 * http://developer.yahoo.net/yui/license.txt
3514 * <script type="text/javascript">
3518 Roo.lib.AnimMgr = new function() {
3535 this.registerElement = function(tween) {
3536 queue[queue.length] = tween;
3538 tween._onStart.fire();
3543 this.unRegister = function(tween, index) {
3544 tween._onComplete.fire();
3545 index = index || getIndex(tween);
3547 queue.splice(index, 1);
3551 if (tweenCount <= 0) {
3557 this.start = function() {
3558 if (thread === null) {
3559 thread = setInterval(this.run, this.delay);
3564 this.stop = function(tween) {
3566 clearInterval(thread);
3568 for (var i = 0, len = queue.length; i < len; ++i) {
3569 if (queue[0].isAnimated()) {
3570 this.unRegister(queue[0], 0);
3579 this.unRegister(tween);
3584 this.run = function() {
3585 for (var i = 0, len = queue.length; i < len; ++i) {
3586 var tween = queue[i];
3587 if (!tween || !tween.isAnimated()) {
3591 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3593 tween.currentFrame += 1;
3595 if (tween.useSeconds) {
3596 correctFrame(tween);
3598 tween._onTween.fire();
3601 Roo.lib.AnimMgr.stop(tween, i);
3606 var getIndex = function(anim) {
3607 for (var i = 0, len = queue.length; i < len; ++i) {
3608 if (queue[i] == anim) {
3616 var correctFrame = function(tween) {
3617 var frames = tween.totalFrames;
3618 var frame = tween.currentFrame;
3619 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3620 var elapsed = (new Date() - tween.getStartTime());
3623 if (elapsed < tween.duration * 1000) {
3624 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3626 tweak = frames - (frame + 1);
3628 if (tweak > 0 && isFinite(tweak)) {
3629 if (tween.currentFrame + tweak >= frames) {
3630 tweak = frames - (frame + 1);
3633 tween.currentFrame += tweak;
3639 * Portions of this file are based on pieces of Yahoo User Interface Library
3640 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3641 * YUI licensed under the BSD License:
3642 * http://developer.yahoo.net/yui/license.txt
3643 * <script type="text/javascript">
3646 Roo.lib.Bezier = new function() {
3648 this.getPosition = function(points, t) {
3649 var n = points.length;
3652 for (var i = 0; i < n; ++i) {
3653 tmp[i] = [points[i][0], points[i][1]];
3656 for (var j = 1; j < n; ++j) {
3657 for (i = 0; i < n - j; ++i) {
3658 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3659 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3663 return [ tmp[0][0], tmp[0][1] ];
3667 * Portions of this file are based on pieces of Yahoo User Interface Library
3668 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3669 * YUI licensed under the BSD License:
3670 * http://developer.yahoo.net/yui/license.txt
3671 * <script type="text/javascript">
3676 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3677 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3680 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3682 var fly = Roo.lib.AnimBase.fly;
3684 var superclass = Y.ColorAnim.superclass;
3685 var proto = Y.ColorAnim.prototype;
3687 proto.toString = function() {
3688 var el = this.getEl();
3689 var id = el.id || el.tagName;
3690 return ("ColorAnim " + id);
3693 proto.patterns.color = /color$/i;
3694 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3695 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3696 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3697 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3700 proto.parseColor = function(s) {
3701 if (s.length == 3) {
3705 var c = this.patterns.hex.exec(s);
3706 if (c && c.length == 4) {
3707 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3710 c = this.patterns.rgb.exec(s);
3711 if (c && c.length == 4) {
3712 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3715 c = this.patterns.hex3.exec(s);
3716 if (c && c.length == 4) {
3717 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3722 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3723 proto.getAttribute = function(attr) {
3724 var el = this.getEl();
3725 if (this.patterns.color.test(attr)) {
3726 var val = fly(el).getStyle(attr);
3728 if (this.patterns.transparent.test(val)) {
3729 var parent = el.parentNode;
3730 val = fly(parent).getStyle(attr);
3732 while (parent && this.patterns.transparent.test(val)) {
3733 parent = parent.parentNode;
3734 val = fly(parent).getStyle(attr);
3735 if (parent.tagName.toUpperCase() == 'HTML') {
3741 val = superclass.getAttribute.call(this, attr);
3746 proto.getAttribute = function(attr) {
3747 var el = this.getEl();
3748 if (this.patterns.color.test(attr)) {
3749 var val = fly(el).getStyle(attr);
3751 if (this.patterns.transparent.test(val)) {
3752 var parent = el.parentNode;
3753 val = fly(parent).getStyle(attr);
3755 while (parent && this.patterns.transparent.test(val)) {
3756 parent = parent.parentNode;
3757 val = fly(parent).getStyle(attr);
3758 if (parent.tagName.toUpperCase() == 'HTML') {
3764 val = superclass.getAttribute.call(this, attr);
3770 proto.doMethod = function(attr, start, end) {
3773 if (this.patterns.color.test(attr)) {
3775 for (var i = 0, len = start.length; i < len; ++i) {
3776 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3779 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3782 val = superclass.doMethod.call(this, attr, start, end);
3788 proto.setRuntimeAttribute = function(attr) {
3789 superclass.setRuntimeAttribute.call(this, attr);
3791 if (this.patterns.color.test(attr)) {
3792 var attributes = this.attributes;
3793 var start = this.parseColor(this.runtimeAttributes[attr].start);
3794 var end = this.parseColor(this.runtimeAttributes[attr].end);
3796 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3797 end = this.parseColor(attributes[attr].by);
3799 for (var i = 0, len = start.length; i < len; ++i) {
3800 end[i] = start[i] + end[i];
3804 this.runtimeAttributes[attr].start = start;
3805 this.runtimeAttributes[attr].end = end;
3811 * Portions of this file are based on pieces of Yahoo User Interface Library
3812 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3813 * YUI licensed under the BSD License:
3814 * http://developer.yahoo.net/yui/license.txt
3815 * <script type="text/javascript">
3821 easeNone: function (t, b, c, d) {
3822 return c * t / d + b;
3826 easeIn: function (t, b, c, d) {
3827 return c * (t /= d) * t + b;
3831 easeOut: function (t, b, c, d) {
3832 return -c * (t /= d) * (t - 2) + b;
3836 easeBoth: function (t, b, c, d) {
3837 if ((t /= d / 2) < 1) {
3838 return c / 2 * t * t + b;
3841 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3845 easeInStrong: function (t, b, c, d) {
3846 return c * (t /= d) * t * t * t + b;
3850 easeOutStrong: function (t, b, c, d) {
3851 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3855 easeBothStrong: function (t, b, c, d) {
3856 if ((t /= d / 2) < 1) {
3857 return c / 2 * t * t * t * t + b;
3860 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3865 elasticIn: function (t, b, c, d, a, p) {
3869 if ((t /= d) == 1) {
3876 if (!a || a < Math.abs(c)) {
3881 var s = p / (2 * Math.PI) * Math.asin(c / a);
3884 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3888 elasticOut: function (t, b, c, d, a, p) {
3892 if ((t /= d) == 1) {
3899 if (!a || a < Math.abs(c)) {
3904 var s = p / (2 * Math.PI) * Math.asin(c / a);
3907 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3911 elasticBoth: function (t, b, c, d, a, p) {
3916 if ((t /= d / 2) == 2) {
3924 if (!a || a < Math.abs(c)) {
3929 var s = p / (2 * Math.PI) * Math.asin(c / a);
3933 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3934 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3936 return a * Math.pow(2, -10 * (t -= 1)) *
3937 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3942 backIn: function (t, b, c, d, s) {
3943 if (typeof s == 'undefined') {
3946 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3950 backOut: function (t, b, c, d, s) {
3951 if (typeof s == 'undefined') {
3954 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3958 backBoth: function (t, b, c, d, s) {
3959 if (typeof s == 'undefined') {
3963 if ((t /= d / 2 ) < 1) {
3964 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3966 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3970 bounceIn: function (t, b, c, d) {
3971 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3975 bounceOut: function (t, b, c, d) {
3976 if ((t /= d) < (1 / 2.75)) {
3977 return c * (7.5625 * t * t) + b;
3978 } else if (t < (2 / 2.75)) {
3979 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3980 } else if (t < (2.5 / 2.75)) {
3981 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3983 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3987 bounceBoth: function (t, b, c, d) {
3989 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3991 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3994 * Portions of this file are based on pieces of Yahoo User Interface Library
3995 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3996 * YUI licensed under the BSD License:
3997 * http://developer.yahoo.net/yui/license.txt
3998 * <script type="text/javascript">
4002 Roo.lib.Motion = function(el, attributes, duration, method) {
4004 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4008 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4012 var superclass = Y.Motion.superclass;
4013 var proto = Y.Motion.prototype;
4015 proto.toString = function() {
4016 var el = this.getEl();
4017 var id = el.id || el.tagName;
4018 return ("Motion " + id);
4021 proto.patterns.points = /^points$/i;
4023 proto.setAttribute = function(attr, val, unit) {
4024 if (this.patterns.points.test(attr)) {
4025 unit = unit || 'px';
4026 superclass.setAttribute.call(this, 'left', val[0], unit);
4027 superclass.setAttribute.call(this, 'top', val[1], unit);
4029 superclass.setAttribute.call(this, attr, val, unit);
4033 proto.getAttribute = function(attr) {
4034 if (this.patterns.points.test(attr)) {
4036 superclass.getAttribute.call(this, 'left'),
4037 superclass.getAttribute.call(this, 'top')
4040 val = superclass.getAttribute.call(this, attr);
4046 proto.doMethod = function(attr, start, end) {
4049 if (this.patterns.points.test(attr)) {
4050 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4051 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4053 val = superclass.doMethod.call(this, attr, start, end);
4058 proto.setRuntimeAttribute = function(attr) {
4059 if (this.patterns.points.test(attr)) {
4060 var el = this.getEl();
4061 var attributes = this.attributes;
4063 var control = attributes['points']['control'] || [];
4067 if (control.length > 0 && !(control[0] instanceof Array)) {
4068 control = [control];
4071 for (i = 0,len = control.length; i < len; ++i) {
4072 tmp[i] = control[i];
4077 Roo.fly(el).position();
4079 if (isset(attributes['points']['from'])) {
4080 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4083 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4086 start = this.getAttribute('points');
4089 if (isset(attributes['points']['to'])) {
4090 end = translateValues.call(this, attributes['points']['to'], start);
4092 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4093 for (i = 0,len = control.length; i < len; ++i) {
4094 control[i] = translateValues.call(this, control[i], start);
4098 } else if (isset(attributes['points']['by'])) {
4099 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4101 for (i = 0,len = control.length; i < len; ++i) {
4102 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4106 this.runtimeAttributes[attr] = [start];
4108 if (control.length > 0) {
4109 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4112 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4115 superclass.setRuntimeAttribute.call(this, attr);
4119 var translateValues = function(val, start) {
4120 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4121 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4126 var isset = function(prop) {
4127 return (typeof prop !== 'undefined');
4131 * Portions of this file are based on pieces of Yahoo User Interface Library
4132 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4133 * YUI licensed under the BSD License:
4134 * http://developer.yahoo.net/yui/license.txt
4135 * <script type="text/javascript">
4139 Roo.lib.Scroll = function(el, attributes, duration, method) {
4141 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4145 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4149 var superclass = Y.Scroll.superclass;
4150 var proto = Y.Scroll.prototype;
4152 proto.toString = function() {
4153 var el = this.getEl();
4154 var id = el.id || el.tagName;
4155 return ("Scroll " + id);
4158 proto.doMethod = function(attr, start, end) {
4161 if (attr == 'scroll') {
4163 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4164 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4168 val = superclass.doMethod.call(this, attr, start, end);
4173 proto.getAttribute = function(attr) {
4175 var el = this.getEl();
4177 if (attr == 'scroll') {
4178 val = [ el.scrollLeft, el.scrollTop ];
4180 val = superclass.getAttribute.call(this, attr);
4186 proto.setAttribute = function(attr, val, unit) {
4187 var el = this.getEl();
4189 if (attr == 'scroll') {
4190 el.scrollLeft = val[0];
4191 el.scrollTop = val[1];
4193 superclass.setAttribute.call(this, attr, val, unit);
4199 * Ext JS Library 1.1.1
4200 * Copyright(c) 2006-2007, Ext JS, LLC.
4202 * Originally Released Under LGPL - original licence link has changed is not relivant.
4205 * <script type="text/javascript">
4209 // nasty IE9 hack - what a pile of crap that is..
4211 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4212 Range.prototype.createContextualFragment = function (html) {
4213 var doc = window.document;
4214 var container = doc.createElement("div");
4215 container.innerHTML = html;
4216 var frag = doc.createDocumentFragment(), n;
4217 while ((n = container.firstChild)) {
4218 frag.appendChild(n);
4225 * @class Roo.DomHelper
4226 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4227 * 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>.
4230 Roo.DomHelper = function(){
4231 var tempTableEl = null;
4232 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4233 var tableRe = /^table|tbody|tr|td$/i;
4235 // build as innerHTML where available
4237 var createHtml = function(o){
4238 if(typeof o == 'string'){
4247 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4248 if(attr == "style"){
4250 if(typeof s == "function"){
4253 if(typeof s == "string"){
4254 b += ' style="' + s + '"';
4255 }else if(typeof s == "object"){
4258 if(typeof s[key] != "function"){
4259 b += key + ":" + s[key] + ";";
4266 b += ' class="' + o["cls"] + '"';
4267 }else if(attr == "htmlFor"){
4268 b += ' for="' + o["htmlFor"] + '"';
4270 b += " " + attr + '="' + o[attr] + '"';
4274 if(emptyTags.test(o.tag)){
4278 var cn = o.children || o.cn;
4280 //http://bugs.kde.org/show_bug.cgi?id=71506
4281 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4282 for(var i = 0, len = cn.length; i < len; i++) {
4283 b += createHtml(cn[i], b);
4286 b += createHtml(cn, b);
4292 b += "</" + o.tag + ">";
4299 var createDom = function(o, parentNode){
4301 // defininition craeted..
4303 if (o.ns && o.ns != 'html') {
4305 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4306 xmlns[o.ns] = o.xmlns;
4309 if (typeof(xmlns[o.ns]) == 'undefined') {
4310 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4316 if (typeof(o) == 'string') {
4317 return parentNode.appendChild(document.createTextNode(o));
4319 o.tag = o.tag || div;
4320 if (o.ns && Roo.isIE) {
4322 o.tag = o.ns + ':' + o.tag;
4325 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4326 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4329 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4330 attr == "style" || typeof o[attr] == "function") { continue; }
4332 if(attr=="cls" && Roo.isIE){
4333 el.className = o["cls"];
4335 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4341 Roo.DomHelper.applyStyles(el, o.style);
4342 var cn = o.children || o.cn;
4344 //http://bugs.kde.org/show_bug.cgi?id=71506
4345 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4346 for(var i = 0, len = cn.length; i < len; i++) {
4347 createDom(cn[i], el);
4354 el.innerHTML = o.html;
4357 parentNode.appendChild(el);
4362 var ieTable = function(depth, s, h, e){
4363 tempTableEl.innerHTML = [s, h, e].join('');
4364 var i = -1, el = tempTableEl;
4365 while(++i < depth && el.firstChild){
4371 // kill repeat to save bytes
4375 tbe = '</tbody>'+te,
4381 * Nasty code for IE's broken table implementation
4383 var insertIntoTable = function(tag, where, el, html){
4385 tempTableEl = document.createElement('div');
4390 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4393 if(where == 'beforebegin'){
4397 before = el.nextSibling;
4400 node = ieTable(4, trs, html, tre);
4402 else if(tag == 'tr'){
4403 if(where == 'beforebegin'){
4406 node = ieTable(3, tbs, html, tbe);
4407 } else if(where == 'afterend'){
4408 before = el.nextSibling;
4410 node = ieTable(3, tbs, html, tbe);
4411 } else{ // INTO a TR
4412 if(where == 'afterbegin'){
4413 before = el.firstChild;
4415 node = ieTable(4, trs, html, tre);
4417 } else if(tag == 'tbody'){
4418 if(where == 'beforebegin'){
4421 node = ieTable(2, ts, html, te);
4422 } else if(where == 'afterend'){
4423 before = el.nextSibling;
4425 node = ieTable(2, ts, html, te);
4427 if(where == 'afterbegin'){
4428 before = el.firstChild;
4430 node = ieTable(3, tbs, html, tbe);
4433 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4436 if(where == 'afterbegin'){
4437 before = el.firstChild;
4439 node = ieTable(2, ts, html, te);
4441 el.insertBefore(node, before);
4446 /** True to force the use of DOM instead of html fragments @type Boolean */
4450 * Returns the markup for the passed Element(s) config
4451 * @param {Object} o The Dom object spec (and children)
4454 markup : function(o){
4455 return createHtml(o);
4459 * Applies a style specification to an element
4460 * @param {String/HTMLElement} el The element to apply styles to
4461 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4462 * a function which returns such a specification.
4464 applyStyles : function(el, styles){
4467 if(typeof styles == "string"){
4468 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4470 while ((matches = re.exec(styles)) != null){
4471 el.setStyle(matches[1], matches[2]);
4473 }else if (typeof styles == "object"){
4474 for (var style in styles){
4475 el.setStyle(style, styles[style]);
4477 }else if (typeof styles == "function"){
4478 Roo.DomHelper.applyStyles(el, styles.call());
4484 * Inserts an HTML fragment into the Dom
4485 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4486 * @param {HTMLElement} el The context element
4487 * @param {String} html The HTML fragmenet
4488 * @return {HTMLElement} The new node
4490 insertHtml : function(where, el, html){
4491 where = where.toLowerCase();
4492 if(el.insertAdjacentHTML){
4493 if(tableRe.test(el.tagName)){
4495 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4501 el.insertAdjacentHTML('BeforeBegin', html);
4502 return el.previousSibling;
4504 el.insertAdjacentHTML('AfterBegin', html);
4505 return el.firstChild;
4507 el.insertAdjacentHTML('BeforeEnd', html);
4508 return el.lastChild;
4510 el.insertAdjacentHTML('AfterEnd', html);
4511 return el.nextSibling;
4513 throw 'Illegal insertion point -> "' + where + '"';
4515 var range = el.ownerDocument.createRange();
4519 range.setStartBefore(el);
4520 frag = range.createContextualFragment(html);
4521 el.parentNode.insertBefore(frag, el);
4522 return el.previousSibling;
4525 range.setStartBefore(el.firstChild);
4526 frag = range.createContextualFragment(html);
4527 el.insertBefore(frag, el.firstChild);
4528 return el.firstChild;
4530 el.innerHTML = html;
4531 return el.firstChild;
4535 range.setStartAfter(el.lastChild);
4536 frag = range.createContextualFragment(html);
4537 el.appendChild(frag);
4538 return el.lastChild;
4540 el.innerHTML = html;
4541 return el.lastChild;
4544 range.setStartAfter(el);
4545 frag = range.createContextualFragment(html);
4546 el.parentNode.insertBefore(frag, el.nextSibling);
4547 return el.nextSibling;
4549 throw 'Illegal insertion point -> "' + where + '"';
4553 * Creates new Dom element(s) and inserts them before el
4554 * @param {String/HTMLElement/Element} el The context element
4555 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4556 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4557 * @return {HTMLElement/Roo.Element} The new node
4559 insertBefore : function(el, o, returnElement){
4560 return this.doInsert(el, o, returnElement, "beforeBegin");
4564 * Creates new Dom element(s) and inserts them after el
4565 * @param {String/HTMLElement/Element} el The context element
4566 * @param {Object} o The Dom object spec (and children)
4567 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4568 * @return {HTMLElement/Roo.Element} The new node
4570 insertAfter : function(el, o, returnElement){
4571 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4575 * Creates new Dom element(s) and inserts them as the first child of el
4576 * @param {String/HTMLElement/Element} el The context element
4577 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4578 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4579 * @return {HTMLElement/Roo.Element} The new node
4581 insertFirst : function(el, o, returnElement){
4582 return this.doInsert(el, o, returnElement, "afterBegin");
4586 doInsert : function(el, o, returnElement, pos, sibling){
4587 el = Roo.getDom(el);
4589 if(this.useDom || o.ns){
4590 newNode = createDom(o, null);
4591 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4593 var html = createHtml(o);
4594 newNode = this.insertHtml(pos, el, html);
4596 return returnElement ? Roo.get(newNode, true) : newNode;
4600 * Creates new Dom element(s) and appends them to el
4601 * @param {String/HTMLElement/Element} el The context element
4602 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4603 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4604 * @return {HTMLElement/Roo.Element} The new node
4606 append : function(el, o, returnElement){
4607 el = Roo.getDom(el);
4609 if(this.useDom || o.ns){
4610 newNode = createDom(o, null);
4611 el.appendChild(newNode);
4613 var html = createHtml(o);
4614 newNode = this.insertHtml("beforeEnd", el, html);
4616 return returnElement ? Roo.get(newNode, true) : newNode;
4620 * Creates new Dom element(s) and overwrites the contents of el with them
4621 * @param {String/HTMLElement/Element} el The context element
4622 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4623 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4624 * @return {HTMLElement/Roo.Element} The new node
4626 overwrite : function(el, o, returnElement){
4627 el = Roo.getDom(el);
4630 while (el.childNodes.length) {
4631 el.removeChild(el.firstChild);
4635 el.innerHTML = createHtml(o);
4638 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4642 * Creates a new Roo.DomHelper.Template from the Dom object spec
4643 * @param {Object} o The Dom object spec (and children)
4644 * @return {Roo.DomHelper.Template} The new template
4646 createTemplate : function(o){
4647 var html = createHtml(o);
4648 return new Roo.Template(html);
4654 * Ext JS Library 1.1.1
4655 * Copyright(c) 2006-2007, Ext JS, LLC.
4657 * Originally Released Under LGPL - original licence link has changed is not relivant.
4660 * <script type="text/javascript">
4664 * @class Roo.Template
4665 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4666 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4669 var t = new Roo.Template({
4670 html : '<div name="{id}">' +
4671 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4673 myformat: function (value, allValues) {
4674 return 'XX' + value;
4677 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4679 * For more information see this blog post with examples:
4680 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4681 - Create Elements using DOM, HTML fragments and Templates</a>.
4683 * @param {Object} cfg - Configuration object.
4685 Roo.Template = function(cfg){
4687 if(cfg instanceof Array){
4689 }else if(arguments.length > 1){
4690 cfg = Array.prototype.join.call(arguments, "");
4694 if (typeof(cfg) == 'object') {
4705 Roo.Template.prototype = {
4708 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
4714 * @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..
4715 * it should be fixed so that template is observable...
4719 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4727 * Returns an HTML fragment of this template with the specified values applied.
4728 * @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'})
4729 * @return {String} The HTML fragment
4734 applyTemplate : function(values){
4735 //Roo.log(["applyTemplate", values]);
4739 return this.compiled(values);
4741 var useF = this.disableFormats !== true;
4742 var fm = Roo.util.Format, tpl = this;
4743 var fn = function(m, name, format, args){
4745 if(format.substr(0, 5) == "this."){
4746 return tpl.call(format.substr(5), values[name], values);
4749 // quoted values are required for strings in compiled templates,
4750 // but for non compiled we need to strip them
4751 // quoted reversed for jsmin
4752 var re = /^\s*['"](.*)["']\s*$/;
4753 args = args.split(',');
4754 for(var i = 0, len = args.length; i < len; i++){
4755 args[i] = args[i].replace(re, "$1");
4757 args = [values[name]].concat(args);
4759 args = [values[name]];
4761 return fm[format].apply(fm, args);
4764 return values[name] !== undefined ? values[name] : "";
4767 return this.html.replace(this.re, fn);
4785 this.loading = true;
4786 this.compiled = false;
4788 var cx = new Roo.data.Connection();
4792 success : function (response) {
4796 _t.set(response.responseText,true);
4802 failure : function(response) {
4803 Roo.log("Template failed to load from " + _t.url);
4810 * Sets the HTML used as the template and optionally compiles it.
4811 * @param {String} html
4812 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4813 * @return {Roo.Template} this
4815 set : function(html, compile){
4817 this.compiled = false;
4825 * True to disable format functions (defaults to false)
4828 disableFormats : false,
4831 * The regular expression used to match template variables
4835 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4838 * Compiles the template into an internal function, eliminating the RegEx overhead.
4839 * @return {Roo.Template} this
4841 compile : function(){
4842 var fm = Roo.util.Format;
4843 var useF = this.disableFormats !== true;
4844 var sep = Roo.isGecko ? "+" : ",";
4845 var fn = function(m, name, format, args){
4847 args = args ? ',' + args : "";
4848 if(format.substr(0, 5) != "this."){
4849 format = "fm." + format + '(';
4851 format = 'this.call("'+ format.substr(5) + '", ';
4855 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4857 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4860 // branched to use + in gecko and [].join() in others
4862 body = "this.compiled = function(values){ return '" +
4863 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4866 body = ["this.compiled = function(values){ return ['"];
4867 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4868 body.push("'].join('');};");
4869 body = body.join('');
4879 // private function used to call members
4880 call : function(fnName, value, allValues){
4881 return this[fnName](value, allValues);
4885 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4886 * @param {String/HTMLElement/Roo.Element} el The context element
4887 * @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'})
4888 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4889 * @return {HTMLElement/Roo.Element} The new node or Element
4891 insertFirst: function(el, values, returnElement){
4892 return this.doInsert('afterBegin', el, values, returnElement);
4896 * Applies the supplied values to the template and inserts the new node(s) before el.
4897 * @param {String/HTMLElement/Roo.Element} el The context element
4898 * @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'})
4899 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4900 * @return {HTMLElement/Roo.Element} The new node or Element
4902 insertBefore: function(el, values, returnElement){
4903 return this.doInsert('beforeBegin', el, values, returnElement);
4907 * Applies the supplied values to the template and inserts the new node(s) after el.
4908 * @param {String/HTMLElement/Roo.Element} el The context element
4909 * @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'})
4910 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4911 * @return {HTMLElement/Roo.Element} The new node or Element
4913 insertAfter : function(el, values, returnElement){
4914 return this.doInsert('afterEnd', el, values, returnElement);
4918 * Applies the supplied values to the template and appends the new node(s) to el.
4919 * @param {String/HTMLElement/Roo.Element} el The context element
4920 * @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'})
4921 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4922 * @return {HTMLElement/Roo.Element} The new node or Element
4924 append : function(el, values, returnElement){
4925 return this.doInsert('beforeEnd', el, values, returnElement);
4928 doInsert : function(where, el, values, returnEl){
4929 el = Roo.getDom(el);
4930 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4931 return returnEl ? Roo.get(newNode, true) : newNode;
4935 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4936 * @param {String/HTMLElement/Roo.Element} el The context element
4937 * @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'})
4938 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4939 * @return {HTMLElement/Roo.Element} The new node or Element
4941 overwrite : function(el, values, returnElement){
4942 el = Roo.getDom(el);
4943 el.innerHTML = this.applyTemplate(values);
4944 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4948 * Alias for {@link #applyTemplate}
4951 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4954 Roo.DomHelper.Template = Roo.Template;
4957 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4958 * @param {String/HTMLElement} el A DOM element or its id
4959 * @returns {Roo.Template} The created template
4962 Roo.Template.from = function(el){
4963 el = Roo.getDom(el);
4964 return new Roo.Template(el.value || el.innerHTML);
4967 * Ext JS Library 1.1.1
4968 * Copyright(c) 2006-2007, Ext JS, LLC.
4970 * Originally Released Under LGPL - original licence link has changed is not relivant.
4973 * <script type="text/javascript">
4978 * This is code is also distributed under MIT license for use
4979 * with jQuery and prototype JavaScript libraries.
4982 * @class Roo.DomQuery
4983 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).
4985 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>
4988 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.
4990 <h4>Element Selectors:</h4>
4992 <li> <b>*</b> any element</li>
4993 <li> <b>E</b> an element with the tag E</li>
4994 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4995 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4996 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4997 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4999 <h4>Attribute Selectors:</h4>
5000 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5002 <li> <b>E[foo]</b> has an attribute "foo"</li>
5003 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5004 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5005 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5006 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5007 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5008 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5010 <h4>Pseudo Classes:</h4>
5012 <li> <b>E:first-child</b> E is the first child of its parent</li>
5013 <li> <b>E:last-child</b> E is the last child of its parent</li>
5014 <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>
5015 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5016 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5017 <li> <b>E:only-child</b> E is the only child of its parent</li>
5018 <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>
5019 <li> <b>E:first</b> the first E in the resultset</li>
5020 <li> <b>E:last</b> the last E in the resultset</li>
5021 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5022 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5023 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5024 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5025 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5026 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5027 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5028 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5029 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5031 <h4>CSS Value Selectors:</h4>
5033 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5034 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5035 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5036 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5037 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5038 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5042 Roo.DomQuery = function(){
5043 var cache = {}, simpleCache = {}, valueCache = {};
5044 var nonSpace = /\S/;
5045 var trimRe = /^\s+|\s+$/g;
5046 var tplRe = /\{(\d+)\}/g;
5047 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5048 var tagTokenRe = /^(#)?([\w-\*]+)/;
5049 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5051 function child(p, index){
5053 var n = p.firstChild;
5055 if(n.nodeType == 1){
5066 while((n = n.nextSibling) && n.nodeType != 1);
5071 while((n = n.previousSibling) && n.nodeType != 1);
5075 function children(d){
5076 var n = d.firstChild, ni = -1;
5078 var nx = n.nextSibling;
5079 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5089 function byClassName(c, a, v){
5093 var r = [], ri = -1, cn;
5094 for(var i = 0, ci; ci = c[i]; i++){
5098 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5099 +' ').indexOf(v) != -1){
5106 function attrValue(n, attr){
5107 if(!n.tagName && typeof n.length != "undefined"){
5116 if(attr == "class" || attr == "className"){
5117 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5119 return n.getAttribute(attr) || n[attr];
5123 function getNodes(ns, mode, tagName){
5124 var result = [], ri = -1, cs;
5128 tagName = tagName || "*";
5129 if(typeof ns.getElementsByTagName != "undefined"){
5133 for(var i = 0, ni; ni = ns[i]; i++){
5134 cs = ni.getElementsByTagName(tagName);
5135 for(var j = 0, ci; ci = cs[j]; j++){
5139 }else if(mode == "/" || mode == ">"){
5140 var utag = tagName.toUpperCase();
5141 for(var i = 0, ni, cn; ni = ns[i]; i++){
5142 cn = ni.children || ni.childNodes;
5143 for(var j = 0, cj; cj = cn[j]; j++){
5144 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5149 }else if(mode == "+"){
5150 var utag = tagName.toUpperCase();
5151 for(var i = 0, n; n = ns[i]; i++){
5152 while((n = n.nextSibling) && n.nodeType != 1);
5153 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5157 }else if(mode == "~"){
5158 for(var i = 0, n; n = ns[i]; i++){
5159 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5168 function concat(a, b){
5172 for(var i = 0, l = b.length; i < l; i++){
5178 function byTag(cs, tagName){
5179 if(cs.tagName || cs == document){
5185 var r = [], ri = -1;
5186 tagName = tagName.toLowerCase();
5187 for(var i = 0, ci; ci = cs[i]; i++){
5188 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5195 function byId(cs, attr, id){
5196 if(cs.tagName || cs == document){
5202 var r = [], ri = -1;
5203 for(var i = 0,ci; ci = cs[i]; i++){
5204 if(ci && ci.id == id){
5212 function byAttribute(cs, attr, value, op, custom){
5213 var r = [], ri = -1, st = custom=="{";
5214 var f = Roo.DomQuery.operators[op];
5215 for(var i = 0, ci; ci = cs[i]; i++){
5218 a = Roo.DomQuery.getStyle(ci, attr);
5220 else if(attr == "class" || attr == "className"){
5221 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
5222 }else if(attr == "for"){
5224 }else if(attr == "href"){
5225 a = ci.getAttribute("href", 2);
5227 a = ci.getAttribute(attr);
5229 if((f && f(a, value)) || (!f && a)){
5236 function byPseudo(cs, name, value){
5237 return Roo.DomQuery.pseudos[name](cs, value);
5240 // This is for IE MSXML which does not support expandos.
5241 // IE runs the same speed using setAttribute, however FF slows way down
5242 // and Safari completely fails so they need to continue to use expandos.
5243 var isIE = window.ActiveXObject ? true : false;
5245 // this eval is stop the compressor from
5246 // renaming the variable to something shorter
5248 /** eval:var:batch */
5253 function nodupIEXml(cs){
5255 cs[0].setAttribute("_nodup", d);
5257 for(var i = 1, len = cs.length; i < len; i++){
5259 if(!c.getAttribute("_nodup") != d){
5260 c.setAttribute("_nodup", d);
5264 for(var i = 0, len = cs.length; i < len; i++){
5265 cs[i].removeAttribute("_nodup");
5274 var len = cs.length, c, i, r = cs, cj, ri = -1;
5275 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5278 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5279 return nodupIEXml(cs);
5283 for(i = 1; c = cs[i]; i++){
5288 for(var j = 0; j < i; j++){
5291 for(j = i+1; cj = cs[j]; j++){
5303 function quickDiffIEXml(c1, c2){
5305 for(var i = 0, len = c1.length; i < len; i++){
5306 c1[i].setAttribute("_qdiff", d);
5309 for(var i = 0, len = c2.length; i < len; i++){
5310 if(c2[i].getAttribute("_qdiff") != d){
5311 r[r.length] = c2[i];
5314 for(var i = 0, len = c1.length; i < len; i++){
5315 c1[i].removeAttribute("_qdiff");
5320 function quickDiff(c1, c2){
5321 var len1 = c1.length;
5325 if(isIE && c1[0].selectSingleNode){
5326 return quickDiffIEXml(c1, c2);
5329 for(var i = 0; i < len1; i++){
5333 for(var i = 0, len = c2.length; i < len; i++){
5334 if(c2[i]._qdiff != d){
5335 r[r.length] = c2[i];
5341 function quickId(ns, mode, root, id){
5343 var d = root.ownerDocument || root;
5344 return d.getElementById(id);
5346 ns = getNodes(ns, mode, "*");
5347 return byId(ns, null, id);
5351 getStyle : function(el, name){
5352 return Roo.fly(el).getStyle(name);
5355 * Compiles a selector/xpath query into a reusable function. The returned function
5356 * takes one parameter "root" (optional), which is the context node from where the query should start.
5357 * @param {String} selector The selector/xpath query
5358 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5359 * @return {Function}
5361 compile : function(path, type){
5362 type = type || "select";
5364 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5365 var q = path, mode, lq;
5366 var tk = Roo.DomQuery.matchers;
5367 var tklen = tk.length;
5370 // accept leading mode switch
5371 var lmode = q.match(modeRe);
5372 if(lmode && lmode[1]){
5373 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5374 q = q.replace(lmode[1], "");
5376 // strip leading slashes
5377 while(path.substr(0, 1)=="/"){
5378 path = path.substr(1);
5381 while(q && lq != q){
5383 var tm = q.match(tagTokenRe);
5384 if(type == "select"){
5387 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5389 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5391 q = q.replace(tm[0], "");
5392 }else if(q.substr(0, 1) != '@'){
5393 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5398 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5400 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5402 q = q.replace(tm[0], "");
5405 while(!(mm = q.match(modeRe))){
5406 var matched = false;
5407 for(var j = 0; j < tklen; j++){
5409 var m = q.match(t.re);
5411 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5414 q = q.replace(m[0], "");
5419 // prevent infinite loop on bad selector
5421 throw 'Error parsing selector, parsing failed at "' + q + '"';
5425 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5426 q = q.replace(mm[1], "");
5429 fn[fn.length] = "return nodup(n);\n}";
5432 * list of variables that need from compression as they are used by eval.
5442 * eval:var:byClassName
5444 * eval:var:byAttribute
5445 * eval:var:attrValue
5453 * Selects a group of elements.
5454 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5455 * @param {Node} root (optional) The start of the query (defaults to document).
5458 select : function(path, root, type){
5459 if(!root || root == document){
5462 if(typeof root == "string"){
5463 root = document.getElementById(root);
5465 var paths = path.split(",");
5467 for(var i = 0, len = paths.length; i < len; i++){
5468 var p = paths[i].replace(trimRe, "");
5470 cache[p] = Roo.DomQuery.compile(p);
5472 throw p + " is not a valid selector";
5475 var result = cache[p](root);
5476 if(result && result != document){
5477 results = results.concat(result);
5480 if(paths.length > 1){
5481 return nodup(results);
5487 * Selects a single element.
5488 * @param {String} selector The selector/xpath query
5489 * @param {Node} root (optional) The start of the query (defaults to document).
5492 selectNode : function(path, root){
5493 return Roo.DomQuery.select(path, root)[0];
5497 * Selects the value of a node, optionally replacing null with the defaultValue.
5498 * @param {String} selector The selector/xpath query
5499 * @param {Node} root (optional) The start of the query (defaults to document).
5500 * @param {String} defaultValue
5502 selectValue : function(path, root, defaultValue){
5503 path = path.replace(trimRe, "");
5504 if(!valueCache[path]){
5505 valueCache[path] = Roo.DomQuery.compile(path, "select");
5507 var n = valueCache[path](root);
5508 n = n[0] ? n[0] : n;
5509 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5510 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5514 * Selects the value of a node, parsing integers and floats.
5515 * @param {String} selector The selector/xpath query
5516 * @param {Node} root (optional) The start of the query (defaults to document).
5517 * @param {Number} defaultValue
5520 selectNumber : function(path, root, defaultValue){
5521 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5522 return parseFloat(v);
5526 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5527 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5528 * @param {String} selector The simple selector to test
5531 is : function(el, ss){
5532 if(typeof el == "string"){
5533 el = document.getElementById(el);
5535 var isArray = (el instanceof Array);
5536 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5537 return isArray ? (result.length == el.length) : (result.length > 0);
5541 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5542 * @param {Array} el An array of elements to filter
5543 * @param {String} selector The simple selector to test
5544 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5545 * the selector instead of the ones that match
5548 filter : function(els, ss, nonMatches){
5549 ss = ss.replace(trimRe, "");
5550 if(!simpleCache[ss]){
5551 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5553 var result = simpleCache[ss](els);
5554 return nonMatches ? quickDiff(result, els) : result;
5558 * Collection of matching regular expressions and code snippets.
5562 select: 'n = byClassName(n, null, " {1} ");'
5564 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5565 select: 'n = byPseudo(n, "{1}", "{2}");'
5567 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5568 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5571 select: 'n = byId(n, null, "{1}");'
5574 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5579 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5580 * 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, > <.
5583 "=" : function(a, v){
5586 "!=" : function(a, v){
5589 "^=" : function(a, v){
5590 return a && a.substr(0, v.length) == v;
5592 "$=" : function(a, v){
5593 return a && a.substr(a.length-v.length) == v;
5595 "*=" : function(a, v){
5596 return a && a.indexOf(v) !== -1;
5598 "%=" : function(a, v){
5599 return (a % v) == 0;
5601 "|=" : function(a, v){
5602 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5604 "~=" : function(a, v){
5605 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5610 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5611 * and the argument (if any) supplied in the selector.
5614 "first-child" : function(c){
5615 var r = [], ri = -1, n;
5616 for(var i = 0, ci; ci = n = c[i]; i++){
5617 while((n = n.previousSibling) && n.nodeType != 1);
5625 "last-child" : function(c){
5626 var r = [], ri = -1, n;
5627 for(var i = 0, ci; ci = n = c[i]; i++){
5628 while((n = n.nextSibling) && n.nodeType != 1);
5636 "nth-child" : function(c, a) {
5637 var r = [], ri = -1;
5638 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5639 var f = (m[1] || 1) - 0, l = m[2] - 0;
5640 for(var i = 0, n; n = c[i]; i++){
5641 var pn = n.parentNode;
5642 if (batch != pn._batch) {
5644 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5645 if(cn.nodeType == 1){
5652 if (l == 0 || n.nodeIndex == l){
5655 } else if ((n.nodeIndex + l) % f == 0){
5663 "only-child" : function(c){
5664 var r = [], ri = -1;;
5665 for(var i = 0, ci; ci = c[i]; i++){
5666 if(!prev(ci) && !next(ci)){
5673 "empty" : function(c){
5674 var r = [], ri = -1;
5675 for(var i = 0, ci; ci = c[i]; i++){
5676 var cns = ci.childNodes, j = 0, cn, empty = true;
5679 if(cn.nodeType == 1 || cn.nodeType == 3){
5691 "contains" : function(c, v){
5692 var r = [], ri = -1;
5693 for(var i = 0, ci; ci = c[i]; i++){
5694 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5701 "nodeValue" : function(c, v){
5702 var r = [], ri = -1;
5703 for(var i = 0, ci; ci = c[i]; i++){
5704 if(ci.firstChild && ci.firstChild.nodeValue == v){
5711 "checked" : function(c){
5712 var r = [], ri = -1;
5713 for(var i = 0, ci; ci = c[i]; i++){
5714 if(ci.checked == true){
5721 "not" : function(c, ss){
5722 return Roo.DomQuery.filter(c, ss, true);
5725 "odd" : function(c){
5726 return this["nth-child"](c, "odd");
5729 "even" : function(c){
5730 return this["nth-child"](c, "even");
5733 "nth" : function(c, a){
5734 return c[a-1] || [];
5737 "first" : function(c){
5741 "last" : function(c){
5742 return c[c.length-1] || [];
5745 "has" : function(c, ss){
5746 var s = Roo.DomQuery.select;
5747 var r = [], ri = -1;
5748 for(var i = 0, ci; ci = c[i]; i++){
5749 if(s(ss, ci).length > 0){
5756 "next" : function(c, ss){
5757 var is = Roo.DomQuery.is;
5758 var r = [], ri = -1;
5759 for(var i = 0, ci; ci = c[i]; i++){
5768 "prev" : function(c, ss){
5769 var is = Roo.DomQuery.is;
5770 var r = [], ri = -1;
5771 for(var i = 0, ci; ci = c[i]; i++){
5784 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5785 * @param {String} path The selector/xpath query
5786 * @param {Node} root (optional) The start of the query (defaults to document).
5791 Roo.query = Roo.DomQuery.select;
5794 * Ext JS Library 1.1.1
5795 * Copyright(c) 2006-2007, Ext JS, LLC.
5797 * Originally Released Under LGPL - original licence link has changed is not relivant.
5800 * <script type="text/javascript">
5804 * @class Roo.util.Observable
5805 * Base class that provides a common interface for publishing events. Subclasses are expected to
5806 * to have a property "events" with all the events defined.<br>
5809 Employee = function(name){
5816 Roo.extend(Employee, Roo.util.Observable);
5818 * @param {Object} config properties to use (incuding events / listeners)
5821 Roo.util.Observable = function(cfg){
5824 this.addEvents(cfg.events || {});
5826 delete cfg.events; // make sure
5829 Roo.apply(this, cfg);
5832 this.on(this.listeners);
5833 delete this.listeners;
5836 Roo.util.Observable.prototype = {
5838 * @cfg {Object} listeners list of events and functions to call for this object,
5842 'click' : function(e) {
5852 * Fires the specified event with the passed parameters (minus the event name).
5853 * @param {String} eventName
5854 * @param {Object...} args Variable number of parameters are passed to handlers
5855 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5857 fireEvent : function(){
5858 var ce = this.events[arguments[0].toLowerCase()];
5859 if(typeof ce == "object"){
5860 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5867 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5870 * Appends an event handler to this component
5871 * @param {String} eventName The type of event to listen for
5872 * @param {Function} handler The method the event invokes
5873 * @param {Object} scope (optional) The scope in which to execute the handler
5874 * function. The handler function's "this" context.
5875 * @param {Object} options (optional) An object containing handler configuration
5876 * properties. This may contain any of the following properties:<ul>
5877 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5878 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5879 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5880 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5881 * by the specified number of milliseconds. If the event fires again within that time, the original
5882 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5885 * <b>Combining Options</b><br>
5886 * Using the options argument, it is possible to combine different types of listeners:<br>
5888 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5890 el.on('click', this.onClick, this, {
5897 * <b>Attaching multiple handlers in 1 call</b><br>
5898 * The method also allows for a single argument to be passed which is a config object containing properties
5899 * which specify multiple handlers.
5908 fn: this.onMouseOver,
5912 fn: this.onMouseOut,
5918 * Or a shorthand syntax which passes the same scope object to all handlers:
5921 'click': this.onClick,
5922 'mouseover': this.onMouseOver,
5923 'mouseout': this.onMouseOut,
5928 addListener : function(eventName, fn, scope, o){
5929 if(typeof eventName == "object"){
5932 if(this.filterOptRe.test(e)){
5935 if(typeof o[e] == "function"){
5937 this.addListener(e, o[e], o.scope, o);
5939 // individual options
5940 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5945 o = (!o || typeof o == "boolean") ? {} : o;
5946 eventName = eventName.toLowerCase();
5947 var ce = this.events[eventName] || true;
5948 if(typeof ce == "boolean"){
5949 ce = new Roo.util.Event(this, eventName);
5950 this.events[eventName] = ce;
5952 ce.addListener(fn, scope, o);
5956 * Removes a listener
5957 * @param {String} eventName The type of event to listen for
5958 * @param {Function} handler The handler to remove
5959 * @param {Object} scope (optional) The scope (this object) for the handler
5961 removeListener : function(eventName, fn, scope){
5962 var ce = this.events[eventName.toLowerCase()];
5963 if(typeof ce == "object"){
5964 ce.removeListener(fn, scope);
5969 * Removes all listeners for this object
5971 purgeListeners : function(){
5972 for(var evt in this.events){
5973 if(typeof this.events[evt] == "object"){
5974 this.events[evt].clearListeners();
5979 relayEvents : function(o, events){
5980 var createHandler = function(ename){
5983 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5986 for(var i = 0, len = events.length; i < len; i++){
5987 var ename = events[i];
5988 if(!this.events[ename]){
5989 this.events[ename] = true;
5991 o.on(ename, createHandler(ename), this);
5996 * Used to define events on this Observable
5997 * @param {Object} object The object with the events defined
5999 addEvents : function(o){
6003 Roo.applyIf(this.events, o);
6007 * Checks to see if this object has any listeners for a specified event
6008 * @param {String} eventName The name of the event to check for
6009 * @return {Boolean} True if the event is being listened for, else false
6011 hasListener : function(eventName){
6012 var e = this.events[eventName];
6013 return typeof e == "object" && e.listeners.length > 0;
6017 * Appends an event handler to this element (shorthand for addListener)
6018 * @param {String} eventName The type of event to listen for
6019 * @param {Function} handler The method the event invokes
6020 * @param {Object} scope (optional) The scope in which to execute the handler
6021 * function. The handler function's "this" context.
6022 * @param {Object} options (optional)
6025 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6027 * Removes a listener (shorthand for removeListener)
6028 * @param {String} eventName The type of event to listen for
6029 * @param {Function} handler The handler to remove
6030 * @param {Object} scope (optional) The scope (this object) for the handler
6033 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6036 * Starts capture on the specified Observable. All events will be passed
6037 * to the supplied function with the event name + standard signature of the event
6038 * <b>before</b> the event is fired. If the supplied function returns false,
6039 * the event will not fire.
6040 * @param {Observable} o The Observable to capture
6041 * @param {Function} fn The function to call
6042 * @param {Object} scope (optional) The scope (this object) for the fn
6045 Roo.util.Observable.capture = function(o, fn, scope){
6046 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6050 * Removes <b>all</b> added captures from the Observable.
6051 * @param {Observable} o The Observable to release
6054 Roo.util.Observable.releaseCapture = function(o){
6055 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6060 var createBuffered = function(h, o, scope){
6061 var task = new Roo.util.DelayedTask();
6063 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6067 var createSingle = function(h, e, fn, scope){
6069 e.removeListener(fn, scope);
6070 return h.apply(scope, arguments);
6074 var createDelayed = function(h, o, scope){
6076 var args = Array.prototype.slice.call(arguments, 0);
6077 setTimeout(function(){
6078 h.apply(scope, args);
6083 Roo.util.Event = function(obj, name){
6086 this.listeners = [];
6089 Roo.util.Event.prototype = {
6090 addListener : function(fn, scope, options){
6091 var o = options || {};
6092 scope = scope || this.obj;
6093 if(!this.isListening(fn, scope)){
6094 var l = {fn: fn, scope: scope, options: o};
6097 h = createDelayed(h, o, scope);
6100 h = createSingle(h, this, fn, scope);
6103 h = createBuffered(h, o, scope);
6106 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6107 this.listeners.push(l);
6109 this.listeners = this.listeners.slice(0);
6110 this.listeners.push(l);
6115 findListener : function(fn, scope){
6116 scope = scope || this.obj;
6117 var ls = this.listeners;
6118 for(var i = 0, len = ls.length; i < len; i++){
6120 if(l.fn == fn && l.scope == scope){
6127 isListening : function(fn, scope){
6128 return this.findListener(fn, scope) != -1;
6131 removeListener : function(fn, scope){
6133 if((index = this.findListener(fn, scope)) != -1){
6135 this.listeners.splice(index, 1);
6137 this.listeners = this.listeners.slice(0);
6138 this.listeners.splice(index, 1);
6145 clearListeners : function(){
6146 this.listeners = [];
6150 var ls = this.listeners, scope, len = ls.length;
6153 var args = Array.prototype.slice.call(arguments, 0);
6154 for(var i = 0; i < len; i++){
6156 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6157 this.firing = false;
6161 this.firing = false;
6168 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6175 * @class Roo.Document
6176 * @extends Roo.util.Observable
6177 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6179 * @param {Object} config the methods and properties of the 'base' class for the application.
6181 * Generic Page handler - implement this to start your app..
6184 * MyProject = new Roo.Document({
6186 'load' : true // your events..
6189 'ready' : function() {
6190 // fired on Roo.onReady()
6195 Roo.Document = function(cfg) {
6200 Roo.util.Observable.call(this,cfg);
6204 Roo.onReady(function() {
6205 _this.fireEvent('ready');
6211 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6213 * Ext JS Library 1.1.1
6214 * Copyright(c) 2006-2007, Ext JS, LLC.
6216 * Originally Released Under LGPL - original licence link has changed is not relivant.
6219 * <script type="text/javascript">
6223 * @class Roo.EventManager
6224 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6225 * several useful events directly.
6226 * See {@link Roo.EventObject} for more details on normalized event objects.
6229 Roo.EventManager = function(){
6230 var docReadyEvent, docReadyProcId, docReadyState = false;
6231 var resizeEvent, resizeTask, textEvent, textSize;
6232 var E = Roo.lib.Event;
6233 var D = Roo.lib.Dom;
6238 var fireDocReady = function(){
6240 docReadyState = true;
6243 clearInterval(docReadyProcId);
6245 if(Roo.isGecko || Roo.isOpera) {
6246 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6249 var defer = document.getElementById("ie-deferred-loader");
6251 defer.onreadystatechange = null;
6252 defer.parentNode.removeChild(defer);
6256 docReadyEvent.fire();
6257 docReadyEvent.clearListeners();
6262 var initDocReady = function(){
6263 docReadyEvent = new Roo.util.Event();
6264 if(Roo.isGecko || Roo.isOpera) {
6265 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6267 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6268 var defer = document.getElementById("ie-deferred-loader");
6269 defer.onreadystatechange = function(){
6270 if(this.readyState == "complete"){
6274 }else if(Roo.isSafari){
6275 docReadyProcId = setInterval(function(){
6276 var rs = document.readyState;
6277 if(rs == "complete") {
6282 // no matter what, make sure it fires on load
6283 E.on(window, "load", fireDocReady);
6286 var createBuffered = function(h, o){
6287 var task = new Roo.util.DelayedTask(h);
6289 // create new event object impl so new events don't wipe out properties
6290 e = new Roo.EventObjectImpl(e);
6291 task.delay(o.buffer, h, null, [e]);
6295 var createSingle = function(h, el, ename, fn){
6297 Roo.EventManager.removeListener(el, ename, fn);
6302 var createDelayed = function(h, o){
6304 // create new event object impl so new events don't wipe out properties
6305 e = new Roo.EventObjectImpl(e);
6306 setTimeout(function(){
6311 var transitionEndVal = false;
6313 var transitionEnd = function()
6315 if (transitionEndVal) {
6316 return transitionEndVal;
6318 var el = document.createElement('div');
6320 var transEndEventNames = {
6321 WebkitTransition : 'webkitTransitionEnd',
6322 MozTransition : 'transitionend',
6323 OTransition : 'oTransitionEnd otransitionend',
6324 transition : 'transitionend'
6327 for (var name in transEndEventNames) {
6328 if (el.style[name] !== undefined) {
6329 transitionEndVal = transEndEventNames[name];
6330 return transitionEndVal ;
6337 var listen = function(element, ename, opt, fn, scope)
6339 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6340 fn = fn || o.fn; scope = scope || o.scope;
6341 var el = Roo.getDom(element);
6345 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6348 if (ename == 'transitionend') {
6349 ename = transitionEnd();
6351 var h = function(e){
6352 e = Roo.EventObject.setEvent(e);
6355 t = e.getTarget(o.delegate, el);
6362 if(o.stopEvent === true){
6365 if(o.preventDefault === true){
6368 if(o.stopPropagation === true){
6369 e.stopPropagation();
6372 if(o.normalized === false){
6376 fn.call(scope || el, e, t, o);
6379 h = createDelayed(h, o);
6382 h = createSingle(h, el, ename, fn);
6385 h = createBuffered(h, o);
6388 fn._handlers = fn._handlers || [];
6391 fn._handlers.push([Roo.id(el), ename, h]);
6395 E.on(el, ename, h); // this adds the actuall listener to the object..
6398 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6399 el.addEventListener("DOMMouseScroll", h, false);
6400 E.on(window, 'unload', function(){
6401 el.removeEventListener("DOMMouseScroll", h, false);
6404 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6405 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6410 var stopListening = function(el, ename, fn){
6411 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6413 for(var i = 0, len = hds.length; i < len; i++){
6415 if(h[0] == id && h[1] == ename){
6422 E.un(el, ename, hd);
6423 el = Roo.getDom(el);
6424 if(ename == "mousewheel" && el.addEventListener){
6425 el.removeEventListener("DOMMouseScroll", hd, false);
6427 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6428 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6432 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6439 * @scope Roo.EventManager
6444 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6445 * object with a Roo.EventObject
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} override If true, the obj passed in becomes
6449 * the execution scope of the listener
6450 * @return {Function} The wrapped function
6453 wrap : function(fn, scope, override){
6455 Roo.EventObject.setEvent(e);
6456 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6461 * Appends an event handler to an element (shorthand for addListener)
6462 * @param {String/HTMLElement} element The html element or id to assign the
6463 * @param {String} eventName The type of event to listen for
6464 * @param {Function} handler The method the event invokes
6465 * @param {Object} scope (optional) The scope in which to execute the handler
6466 * function. The handler function's "this" context.
6467 * @param {Object} options (optional) An object containing handler configuration
6468 * properties. This may contain any of the following properties:<ul>
6469 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6470 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6471 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6472 * <li>preventDefault {Boolean} True to prevent the default action</li>
6473 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6474 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6475 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6476 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6477 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6478 * by the specified number of milliseconds. If the event fires again within that time, the original
6479 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6482 * <b>Combining Options</b><br>
6483 * Using the options argument, it is possible to combine different types of listeners:<br>
6485 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6487 el.on('click', this.onClick, this, {
6494 * <b>Attaching multiple handlers in 1 call</b><br>
6495 * The method also allows for a single argument to be passed which is a config object containing properties
6496 * which specify multiple handlers.
6506 fn: this.onMouseOver
6515 * Or a shorthand syntax:<br>
6518 'click' : this.onClick,
6519 'mouseover' : this.onMouseOver,
6520 'mouseout' : this.onMouseOut
6524 addListener : function(element, eventName, fn, scope, options){
6525 if(typeof eventName == "object"){
6531 if(typeof o[e] == "function"){
6533 listen(element, e, o, o[e], o.scope);
6535 // individual options
6536 listen(element, e, o[e]);
6541 return listen(element, eventName, options, fn, scope);
6545 * Removes an event handler
6547 * @param {String/HTMLElement} element The id or html element to remove the
6549 * @param {String} eventName The type of event
6550 * @param {Function} fn
6551 * @return {Boolean} True if a listener was actually removed
6553 removeListener : function(element, eventName, fn){
6554 return stopListening(element, eventName, fn);
6558 * Fires when the document is ready (before onload and before images are loaded). Can be
6559 * accessed shorthanded Roo.onReady().
6560 * @param {Function} fn The method the event invokes
6561 * @param {Object} scope An object that becomes the scope of the handler
6562 * @param {boolean} options
6564 onDocumentReady : function(fn, scope, options){
6565 if(docReadyState){ // if it already fired
6566 docReadyEvent.addListener(fn, scope, options);
6567 docReadyEvent.fire();
6568 docReadyEvent.clearListeners();
6574 docReadyEvent.addListener(fn, scope, options);
6578 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6579 * @param {Function} fn The method the event invokes
6580 * @param {Object} scope An object that becomes the scope of the handler
6581 * @param {boolean} options
6583 onWindowResize : function(fn, scope, options){
6585 resizeEvent = new Roo.util.Event();
6586 resizeTask = new Roo.util.DelayedTask(function(){
6587 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6589 E.on(window, "resize", function(){
6591 resizeTask.delay(50);
6593 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6597 resizeEvent.addListener(fn, scope, options);
6601 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6602 * @param {Function} fn The method the event invokes
6603 * @param {Object} scope An object that becomes the scope of the handler
6604 * @param {boolean} options
6606 onTextResize : function(fn, scope, options){
6608 textEvent = new Roo.util.Event();
6609 var textEl = new Roo.Element(document.createElement('div'));
6610 textEl.dom.className = 'x-text-resize';
6611 textEl.dom.innerHTML = 'X';
6612 textEl.appendTo(document.body);
6613 textSize = textEl.dom.offsetHeight;
6614 setInterval(function(){
6615 if(textEl.dom.offsetHeight != textSize){
6616 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6618 }, this.textResizeInterval);
6620 textEvent.addListener(fn, scope, options);
6624 * Removes the passed window resize listener.
6625 * @param {Function} fn The method the event invokes
6626 * @param {Object} scope The scope of handler
6628 removeResizeListener : function(fn, scope){
6630 resizeEvent.removeListener(fn, scope);
6635 fireResize : function(){
6637 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6641 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6645 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6647 textResizeInterval : 50
6652 * @scopeAlias pub=Roo.EventManager
6656 * Appends an event handler to an element (shorthand for addListener)
6657 * @param {String/HTMLElement} element The html element or id to assign the
6658 * @param {String} eventName The type of event to listen for
6659 * @param {Function} handler The method the event invokes
6660 * @param {Object} scope (optional) The scope in which to execute the handler
6661 * function. The handler function's "this" context.
6662 * @param {Object} options (optional) An object containing handler configuration
6663 * properties. This may contain any of the following properties:<ul>
6664 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6665 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6666 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6667 * <li>preventDefault {Boolean} True to prevent the default action</li>
6668 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6669 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6670 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6671 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6672 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6673 * by the specified number of milliseconds. If the event fires again within that time, the original
6674 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6677 * <b>Combining Options</b><br>
6678 * Using the options argument, it is possible to combine different types of listeners:<br>
6680 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6682 el.on('click', this.onClick, this, {
6689 * <b>Attaching multiple handlers in 1 call</b><br>
6690 * The method also allows for a single argument to be passed which is a config object containing properties
6691 * which specify multiple handlers.
6701 fn: this.onMouseOver
6710 * Or a shorthand syntax:<br>
6713 'click' : this.onClick,
6714 'mouseover' : this.onMouseOver,
6715 'mouseout' : this.onMouseOut
6719 pub.on = pub.addListener;
6720 pub.un = pub.removeListener;
6722 pub.stoppedMouseDownEvent = new Roo.util.Event();
6726 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6727 * @param {Function} fn The method the event invokes
6728 * @param {Object} scope An object that becomes the scope of the handler
6729 * @param {boolean} override If true, the obj passed in becomes
6730 * the execution scope of the listener
6734 Roo.onReady = Roo.EventManager.onDocumentReady;
6736 Roo.onReady(function(){
6737 var bd = Roo.get(document.body);
6742 : Roo.isIE11 ? "roo-ie11"
6743 : Roo.isEdge ? "roo-edge"
6744 : Roo.isGecko ? "roo-gecko"
6745 : Roo.isOpera ? "roo-opera"
6746 : Roo.isSafari ? "roo-safari" : ""];
6749 cls.push("roo-mac");
6752 cls.push("roo-linux");
6755 cls.push("roo-ios");
6758 cls.push("roo-touch");
6760 if(Roo.isBorderBox){
6761 cls.push('roo-border-box');
6763 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6764 var p = bd.dom.parentNode;
6766 p.className += ' roo-strict';
6769 bd.addClass(cls.join(' '));
6773 * @class Roo.EventObject
6774 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6775 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6778 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6780 var target = e.getTarget();
6783 var myDiv = Roo.get("myDiv");
6784 myDiv.on("click", handleClick);
6786 Roo.EventManager.on("myDiv", 'click', handleClick);
6787 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6791 Roo.EventObject = function(){
6793 var E = Roo.lib.Event;
6795 // safari keypress events for special keys return bad keycodes
6798 63235 : 39, // right
6801 63276 : 33, // page up
6802 63277 : 34, // page down
6803 63272 : 46, // delete
6808 // normalize button clicks
6809 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6810 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6812 Roo.EventObjectImpl = function(e){
6814 this.setEvent(e.browserEvent || e);
6817 Roo.EventObjectImpl.prototype = {
6819 * Used to fix doc tools.
6820 * @scope Roo.EventObject.prototype
6826 /** The normal browser event */
6827 browserEvent : null,
6828 /** The button pressed in a mouse event */
6830 /** True if the shift key was down during the event */
6832 /** True if the control key was down during the event */
6834 /** True if the alt key was down during the event */
6893 setEvent : function(e){
6894 if(e == this || (e && e.browserEvent)){ // already wrapped
6897 this.browserEvent = e;
6899 // normalize buttons
6900 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6901 if(e.type == 'click' && this.button == -1){
6905 this.shiftKey = e.shiftKey;
6906 // mac metaKey behaves like ctrlKey
6907 this.ctrlKey = e.ctrlKey || e.metaKey;
6908 this.altKey = e.altKey;
6909 // in getKey these will be normalized for the mac
6910 this.keyCode = e.keyCode;
6911 // keyup warnings on firefox.
6912 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6913 // cache the target for the delayed and or buffered events
6914 this.target = E.getTarget(e);
6916 this.xy = E.getXY(e);
6919 this.shiftKey = false;
6920 this.ctrlKey = false;
6921 this.altKey = false;
6931 * Stop the event (preventDefault and stopPropagation)
6933 stopEvent : function(){
6934 if(this.browserEvent){
6935 if(this.browserEvent.type == 'mousedown'){
6936 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6938 E.stopEvent(this.browserEvent);
6943 * Prevents the browsers default handling of the event.
6945 preventDefault : function(){
6946 if(this.browserEvent){
6947 E.preventDefault(this.browserEvent);
6952 isNavKeyPress : function(){
6953 var k = this.keyCode;
6954 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6955 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6958 isSpecialKey : function(){
6959 var k = this.keyCode;
6960 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6961 (k == 16) || (k == 17) ||
6962 (k >= 18 && k <= 20) ||
6963 (k >= 33 && k <= 35) ||
6964 (k >= 36 && k <= 39) ||
6965 (k >= 44 && k <= 45);
6968 * Cancels bubbling of the event.
6970 stopPropagation : function(){
6971 if(this.browserEvent){
6972 if(this.type == 'mousedown'){
6973 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6975 E.stopPropagation(this.browserEvent);
6980 * Gets the key code for the event.
6983 getCharCode : function(){
6984 return this.charCode || this.keyCode;
6988 * Returns a normalized keyCode for the event.
6989 * @return {Number} The key code
6991 getKey : function(){
6992 var k = this.keyCode || this.charCode;
6993 return Roo.isSafari ? (safariKeys[k] || k) : k;
6997 * Gets the x coordinate of the event.
7000 getPageX : function(){
7005 * Gets the y coordinate of the event.
7008 getPageY : function(){
7013 * Gets the time of the event.
7016 getTime : function(){
7017 if(this.browserEvent){
7018 return E.getTime(this.browserEvent);
7024 * Gets the page coordinates of the event.
7025 * @return {Array} The xy values like [x, y]
7032 * Gets the target for the event.
7033 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7034 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7035 search as a number or element (defaults to 10 || document.body)
7036 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7037 * @return {HTMLelement}
7039 getTarget : function(selector, maxDepth, returnEl){
7040 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7043 * Gets the related target.
7044 * @return {HTMLElement}
7046 getRelatedTarget : function(){
7047 if(this.browserEvent){
7048 return E.getRelatedTarget(this.browserEvent);
7054 * Normalizes mouse wheel delta across browsers
7055 * @return {Number} The delta
7057 getWheelDelta : function(){
7058 var e = this.browserEvent;
7060 if(e.wheelDelta){ /* IE/Opera. */
7061 delta = e.wheelDelta/120;
7062 }else if(e.detail){ /* Mozilla case. */
7063 delta = -e.detail/3;
7069 * Returns true if the control, meta, shift or alt key was pressed during this event.
7072 hasModifier : function(){
7073 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7077 * Returns true if the target of this event equals el or is a child of el
7078 * @param {String/HTMLElement/Element} el
7079 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7082 within : function(el, related){
7083 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7084 return t && Roo.fly(el).contains(t);
7087 getPoint : function(){
7088 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7092 return new Roo.EventObjectImpl();
7097 * Ext JS Library 1.1.1
7098 * Copyright(c) 2006-2007, Ext JS, LLC.
7100 * Originally Released Under LGPL - original licence link has changed is not relivant.
7103 * <script type="text/javascript">
7107 // was in Composite Element!??!?!
7110 var D = Roo.lib.Dom;
7111 var E = Roo.lib.Event;
7112 var A = Roo.lib.Anim;
7114 // local style camelizing for speed
7116 var camelRe = /(-[a-z])/gi;
7117 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7118 var view = document.defaultView;
7121 * @class Roo.Element
7122 * Represents an Element in the DOM.<br><br>
7125 var el = Roo.get("my-div");
7128 var el = getEl("my-div");
7130 // or with a DOM element
7131 var el = Roo.get(myDivElement);
7133 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7134 * each call instead of constructing a new one.<br><br>
7135 * <b>Animations</b><br />
7136 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7137 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7139 Option Default Description
7140 --------- -------- ---------------------------------------------
7141 duration .35 The duration of the animation in seconds
7142 easing easeOut The YUI easing method
7143 callback none A function to execute when the anim completes
7144 scope this The scope (this) of the callback function
7146 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7147 * manipulate the animation. Here's an example:
7149 var el = Roo.get("my-div");
7154 // default animation
7155 el.setWidth(100, true);
7157 // animation with some options set
7164 // using the "anim" property to get the Anim object
7170 el.setWidth(100, opt);
7172 if(opt.anim.isAnimated()){
7176 * <b> Composite (Collections of) Elements</b><br />
7177 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7178 * @constructor Create a new Element directly.
7179 * @param {String/HTMLElement} element
7180 * @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).
7182 Roo.Element = function(element, forceNew)
7184 var dom = typeof element == "string" ?
7185 document.getElementById(element) : element;
7187 this.listeners = {};
7189 if(!dom){ // invalid id/element
7193 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7194 return Roo.Element.cache[id];
7204 * The DOM element ID
7207 this.id = id || Roo.id(dom);
7209 return this; // assumed for cctor?
7212 var El = Roo.Element;
7216 * The element's default display mode (defaults to "")
7219 originalDisplay : "",
7222 // note this is overridden in BS version..
7225 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7231 * Sets the element's visibility mode. When setVisible() is called it
7232 * will use this to determine whether to set the visibility or the display property.
7233 * @param visMode Element.VISIBILITY or Element.DISPLAY
7234 * @return {Roo.Element} this
7236 setVisibilityMode : function(visMode){
7237 this.visibilityMode = visMode;
7241 * Convenience method for setVisibilityMode(Element.DISPLAY)
7242 * @param {String} display (optional) What to set display to when visible
7243 * @return {Roo.Element} this
7245 enableDisplayMode : function(display){
7246 this.setVisibilityMode(El.DISPLAY);
7247 if(typeof display != "undefined") { this.originalDisplay = display; }
7252 * 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)
7253 * @param {String} selector The simple selector to test
7254 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7255 search as a number or element (defaults to 10 || document.body)
7256 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7257 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7259 findParent : function(simpleSelector, maxDepth, returnEl){
7260 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7261 maxDepth = maxDepth || 50;
7262 if(typeof maxDepth != "number"){
7263 stopEl = Roo.getDom(maxDepth);
7266 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7267 if(dq.is(p, simpleSelector)){
7268 return returnEl ? Roo.get(p) : p;
7278 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7279 * @param {String} selector The simple selector to test
7280 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7281 search as a number or element (defaults to 10 || document.body)
7282 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7283 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7285 findParentNode : function(simpleSelector, maxDepth, returnEl){
7286 var p = Roo.fly(this.dom.parentNode, '_internal');
7287 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7291 * Looks at the scrollable parent element
7293 findScrollableParent : function()
7295 var overflowRegex = /(auto|scroll)/;
7297 if(this.getStyle('position') === 'fixed'){
7298 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7301 var excludeStaticParent = this.getStyle('position') === "absolute";
7303 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7305 if (excludeStaticParent && parent.getStyle('position') === "static") {
7309 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7313 if(parent.dom.nodeName.toLowerCase() == 'body'){
7314 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7318 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7322 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7323 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7324 * @param {String} selector The simple selector to test
7325 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7326 search as a number or element (defaults to 10 || document.body)
7327 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7329 up : function(simpleSelector, maxDepth){
7330 return this.findParentNode(simpleSelector, maxDepth, true);
7336 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7337 * @param {String} selector The simple selector to test
7338 * @return {Boolean} True if this element matches the selector, else false
7340 is : function(simpleSelector){
7341 return Roo.DomQuery.is(this.dom, simpleSelector);
7345 * Perform animation on this element.
7346 * @param {Object} args The YUI animation control args
7347 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7348 * @param {Function} onComplete (optional) Function to call when animation completes
7349 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7350 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7351 * @return {Roo.Element} this
7353 animate : function(args, duration, onComplete, easing, animType){
7354 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7359 * @private Internal animation call
7361 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7362 animType = animType || 'run';
7364 var anim = Roo.lib.Anim[animType](
7366 (opt.duration || defaultDur) || .35,
7367 (opt.easing || defaultEase) || 'easeOut',
7369 Roo.callback(cb, this);
7370 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7378 // private legacy anim prep
7379 preanim : function(a, i){
7380 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7384 * Removes worthless text nodes
7385 * @param {Boolean} forceReclean (optional) By default the element
7386 * keeps track if it has been cleaned already so
7387 * you can call this over and over. However, if you update the element and
7388 * need to force a reclean, you can pass true.
7390 clean : function(forceReclean){
7391 if(this.isCleaned && forceReclean !== true){
7395 var d = this.dom, n = d.firstChild, ni = -1;
7397 var nx = n.nextSibling;
7398 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7405 this.isCleaned = true;
7410 calcOffsetsTo : function(el){
7413 var restorePos = false;
7414 if(el.getStyle('position') == 'static'){
7415 el.position('relative');
7420 while(op && op != d && op.tagName != 'HTML'){
7423 op = op.offsetParent;
7426 el.position('static');
7432 * Scrolls this element into view within the passed container.
7433 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7434 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7435 * @return {Roo.Element} this
7437 scrollIntoView : function(container, hscroll){
7438 var c = Roo.getDom(container) || document.body;
7441 var o = this.calcOffsetsTo(c),
7444 b = t+el.offsetHeight,
7445 r = l+el.offsetWidth;
7447 var ch = c.clientHeight;
7448 var ct = parseInt(c.scrollTop, 10);
7449 var cl = parseInt(c.scrollLeft, 10);
7451 var cr = cl + c.clientWidth;
7459 if(hscroll !== false){
7463 c.scrollLeft = r-c.clientWidth;
7470 scrollChildIntoView : function(child, hscroll){
7471 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7475 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7476 * the new height may not be available immediately.
7477 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7478 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7479 * @param {Function} onComplete (optional) Function to call when animation completes
7480 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7481 * @return {Roo.Element} this
7483 autoHeight : function(animate, duration, onComplete, easing){
7484 var oldHeight = this.getHeight();
7486 this.setHeight(1); // force clipping
7487 setTimeout(function(){
7488 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7490 this.setHeight(height);
7492 if(typeof onComplete == "function"){
7496 this.setHeight(oldHeight); // restore original height
7497 this.setHeight(height, animate, duration, function(){
7499 if(typeof onComplete == "function") { onComplete(); }
7500 }.createDelegate(this), easing);
7502 }.createDelegate(this), 0);
7507 * Returns true if this element is an ancestor of the passed element
7508 * @param {HTMLElement/String} el The element to check
7509 * @return {Boolean} True if this element is an ancestor of el, else false
7511 contains : function(el){
7512 if(!el){return false;}
7513 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7517 * Checks whether the element is currently visible using both visibility and display properties.
7518 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7519 * @return {Boolean} True if the element is currently visible, else false
7521 isVisible : function(deep) {
7522 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7523 if(deep !== true || !vis){
7526 var p = this.dom.parentNode;
7527 while(p && p.tagName.toLowerCase() != "body"){
7528 if(!Roo.fly(p, '_isVisible').isVisible()){
7537 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7538 * @param {String} selector The CSS selector
7539 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7540 * @return {CompositeElement/CompositeElementLite} The composite element
7542 select : function(selector, unique){
7543 return El.select(selector, unique, this.dom);
7547 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7548 * @param {String} selector The CSS selector
7549 * @return {Array} An array of the matched nodes
7551 query : function(selector, unique){
7552 return Roo.DomQuery.select(selector, this.dom);
7556 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7557 * @param {String} selector The CSS selector
7558 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7559 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7561 child : function(selector, returnDom){
7562 var n = Roo.DomQuery.selectNode(selector, this.dom);
7563 return returnDom ? n : Roo.get(n);
7567 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7568 * @param {String} selector The CSS selector
7569 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7570 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7572 down : function(selector, returnDom){
7573 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7574 return returnDom ? n : Roo.get(n);
7578 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7579 * @param {String} group The group the DD object is member of
7580 * @param {Object} config The DD config object
7581 * @param {Object} overrides An object containing methods to override/implement on the DD object
7582 * @return {Roo.dd.DD} The DD object
7584 initDD : function(group, config, overrides){
7585 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7586 return Roo.apply(dd, overrides);
7590 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7591 * @param {String} group The group the DDProxy object is member of
7592 * @param {Object} config The DDProxy config object
7593 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7594 * @return {Roo.dd.DDProxy} The DDProxy object
7596 initDDProxy : function(group, config, overrides){
7597 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7598 return Roo.apply(dd, overrides);
7602 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7603 * @param {String} group The group the DDTarget object is member of
7604 * @param {Object} config The DDTarget config object
7605 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7606 * @return {Roo.dd.DDTarget} The DDTarget object
7608 initDDTarget : function(group, config, overrides){
7609 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7610 return Roo.apply(dd, overrides);
7614 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7615 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7616 * @param {Boolean} visible Whether the element is visible
7617 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7618 * @return {Roo.Element} this
7620 setVisible : function(visible, animate){
7622 if(this.visibilityMode == El.DISPLAY){
7623 this.setDisplayed(visible);
7626 this.dom.style.visibility = visible ? "visible" : "hidden";
7629 // closure for composites
7631 var visMode = this.visibilityMode;
7633 this.setOpacity(.01);
7634 this.setVisible(true);
7636 this.anim({opacity: { to: (visible?1:0) }},
7637 this.preanim(arguments, 1),
7638 null, .35, 'easeIn', function(){
7640 if(visMode == El.DISPLAY){
7641 dom.style.display = "none";
7643 dom.style.visibility = "hidden";
7645 Roo.get(dom).setOpacity(1);
7653 * Returns true if display is not "none"
7656 isDisplayed : function() {
7657 return this.getStyle("display") != "none";
7661 * Toggles the element's visibility or display, depending on visibility mode.
7662 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7663 * @return {Roo.Element} this
7665 toggle : function(animate){
7666 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7671 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7672 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7673 * @return {Roo.Element} this
7675 setDisplayed : function(value) {
7676 if(typeof value == "boolean"){
7677 value = value ? this.originalDisplay : "none";
7679 this.setStyle("display", value);
7684 * Tries to focus the element. Any exceptions are caught and ignored.
7685 * @return {Roo.Element} this
7687 focus : function() {
7695 * Tries to blur the element. Any exceptions are caught and ignored.
7696 * @return {Roo.Element} this
7706 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7707 * @param {String/Array} className The CSS class to add, or an array of classes
7708 * @return {Roo.Element} this
7710 addClass : function(className){
7711 if(className instanceof Array){
7712 for(var i = 0, len = className.length; i < len; i++) {
7713 this.addClass(className[i]);
7716 if(className && !this.hasClass(className)){
7717 if (this.dom instanceof SVGElement) {
7718 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
7720 this.dom.className = this.dom.className + " " + className;
7728 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7729 * @param {String/Array} className The CSS class to add, or an array of classes
7730 * @return {Roo.Element} this
7732 radioClass : function(className){
7733 var siblings = this.dom.parentNode.childNodes;
7734 for(var i = 0; i < siblings.length; i++) {
7735 var s = siblings[i];
7736 if(s.nodeType == 1){
7737 Roo.get(s).removeClass(className);
7740 this.addClass(className);
7745 * Removes one or more CSS classes from the element.
7746 * @param {String/Array} className The CSS class to remove, or an array of classes
7747 * @return {Roo.Element} this
7749 removeClass : function(className){
7751 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
7752 if(!className || !cn){
7755 if(className instanceof Array){
7756 for(var i = 0, len = className.length; i < len; i++) {
7757 this.removeClass(className[i]);
7760 if(this.hasClass(className)){
7761 var re = this.classReCache[className];
7763 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7764 this.classReCache[className] = re;
7766 if (this.dom instanceof SVGElement) {
7767 this.dom.className.baseVal = cn.replace(re, " ");
7769 this.dom.className = cn.replace(re, " ");
7780 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7781 * @param {String} className The CSS class to toggle
7782 * @return {Roo.Element} this
7784 toggleClass : function(className){
7785 if(this.hasClass(className)){
7786 this.removeClass(className);
7788 this.addClass(className);
7794 * Checks if the specified CSS class exists on this element's DOM node.
7795 * @param {String} className The CSS class to check for
7796 * @return {Boolean} True if the class exists, else false
7798 hasClass : function(className){
7799 if (this.dom instanceof SVGElement) {
7800 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
7802 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7806 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7807 * @param {String} oldClassName The CSS class to replace
7808 * @param {String} newClassName The replacement CSS class
7809 * @return {Roo.Element} this
7811 replaceClass : function(oldClassName, newClassName){
7812 this.removeClass(oldClassName);
7813 this.addClass(newClassName);
7818 * Returns an object with properties matching the styles requested.
7819 * For example, el.getStyles('color', 'font-size', 'width') might return
7820 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7821 * @param {String} style1 A style name
7822 * @param {String} style2 A style name
7823 * @param {String} etc.
7824 * @return {Object} The style object
7826 getStyles : function(){
7827 var a = arguments, len = a.length, r = {};
7828 for(var i = 0; i < len; i++){
7829 r[a[i]] = this.getStyle(a[i]);
7835 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7836 * @param {String} property The style property whose value is returned.
7837 * @return {String} The current value of the style property for this element.
7839 getStyle : function(){
7840 return view && view.getComputedStyle ?
7842 var el = this.dom, v, cs, camel;
7843 if(prop == 'float'){
7846 if(el.style && (v = el.style[prop])){
7849 if(cs = view.getComputedStyle(el, "")){
7850 if(!(camel = propCache[prop])){
7851 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7858 var el = this.dom, v, cs, camel;
7859 if(prop == 'opacity'){
7860 if(typeof el.style.filter == 'string'){
7861 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7863 var fv = parseFloat(m[1]);
7865 return fv ? fv / 100 : 0;
7870 }else if(prop == 'float'){
7871 prop = "styleFloat";
7873 if(!(camel = propCache[prop])){
7874 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7876 if(v = el.style[camel]){
7879 if(cs = el.currentStyle){
7887 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7888 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7889 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7890 * @return {Roo.Element} this
7892 setStyle : function(prop, value){
7893 if(typeof prop == "string"){
7895 if (prop == 'float') {
7896 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7901 if(!(camel = propCache[prop])){
7902 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7905 if(camel == 'opacity') {
7906 this.setOpacity(value);
7908 this.dom.style[camel] = value;
7911 for(var style in prop){
7912 if(typeof prop[style] != "function"){
7913 this.setStyle(style, prop[style]);
7921 * More flexible version of {@link #setStyle} for setting style properties.
7922 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7923 * a function which returns such a specification.
7924 * @return {Roo.Element} this
7926 applyStyles : function(style){
7927 Roo.DomHelper.applyStyles(this.dom, style);
7932 * 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).
7933 * @return {Number} The X position of the element
7936 return D.getX(this.dom);
7940 * 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).
7941 * @return {Number} The Y position of the element
7944 return D.getY(this.dom);
7948 * 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).
7949 * @return {Array} The XY position of the element
7952 return D.getXY(this.dom);
7956 * 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).
7957 * @param {Number} The X position of the element
7958 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7959 * @return {Roo.Element} this
7961 setX : function(x, animate){
7963 D.setX(this.dom, x);
7965 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7971 * 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).
7972 * @param {Number} The Y position of the element
7973 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7974 * @return {Roo.Element} this
7976 setY : function(y, animate){
7978 D.setY(this.dom, y);
7980 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7986 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7987 * @param {String} left The left CSS property value
7988 * @return {Roo.Element} this
7990 setLeft : function(left){
7991 this.setStyle("left", this.addUnits(left));
7996 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7997 * @param {String} top The top CSS property value
7998 * @return {Roo.Element} this
8000 setTop : function(top){
8001 this.setStyle("top", this.addUnits(top));
8006 * Sets the element's CSS right style.
8007 * @param {String} right The right CSS property value
8008 * @return {Roo.Element} this
8010 setRight : function(right){
8011 this.setStyle("right", this.addUnits(right));
8016 * Sets the element's CSS bottom style.
8017 * @param {String} bottom The bottom CSS property value
8018 * @return {Roo.Element} this
8020 setBottom : function(bottom){
8021 this.setStyle("bottom", this.addUnits(bottom));
8026 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8027 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8028 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8029 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 setXY : function(pos, animate){
8034 D.setXY(this.dom, pos);
8036 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8042 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8043 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8044 * @param {Number} x X value for new position (coordinates are page-based)
8045 * @param {Number} y Y value for new position (coordinates are page-based)
8046 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8047 * @return {Roo.Element} this
8049 setLocation : function(x, y, animate){
8050 this.setXY([x, y], this.preanim(arguments, 2));
8055 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8056 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8057 * @param {Number} x X value for new position (coordinates are page-based)
8058 * @param {Number} y Y value for new position (coordinates are page-based)
8059 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8060 * @return {Roo.Element} this
8062 moveTo : function(x, y, animate){
8063 this.setXY([x, y], this.preanim(arguments, 2));
8068 * Returns the region of the given element.
8069 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8070 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8072 getRegion : function(){
8073 return D.getRegion(this.dom);
8077 * Returns the offset height of the element
8078 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8079 * @return {Number} The element's height
8081 getHeight : function(contentHeight){
8082 var h = this.dom.offsetHeight || 0;
8083 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8087 * Returns the offset width of the element
8088 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8089 * @return {Number} The element's width
8091 getWidth : function(contentWidth){
8092 var w = this.dom.offsetWidth || 0;
8093 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8097 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8098 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8099 * if a height has not been set using CSS.
8102 getComputedHeight : function(){
8103 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8105 h = parseInt(this.getStyle('height'), 10) || 0;
8106 if(!this.isBorderBox()){
8107 h += this.getFrameWidth('tb');
8114 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8115 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8116 * if a width has not been set using CSS.
8119 getComputedWidth : function(){
8120 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8122 w = parseInt(this.getStyle('width'), 10) || 0;
8123 if(!this.isBorderBox()){
8124 w += this.getFrameWidth('lr');
8131 * Returns the size of the element.
8132 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8133 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8135 getSize : function(contentSize){
8136 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8140 * Returns the width and height of the viewport.
8141 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8143 getViewSize : function(){
8144 var d = this.dom, doc = document, aw = 0, ah = 0;
8145 if(d == doc || d == doc.body){
8146 return {width : D.getViewWidth(), height: D.getViewHeight()};
8149 width : d.clientWidth,
8150 height: d.clientHeight
8156 * Returns the value of the "value" attribute
8157 * @param {Boolean} asNumber true to parse the value as a number
8158 * @return {String/Number}
8160 getValue : function(asNumber){
8161 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8165 adjustWidth : function(width){
8166 if(typeof width == "number"){
8167 if(this.autoBoxAdjust && !this.isBorderBox()){
8168 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8178 adjustHeight : function(height){
8179 if(typeof height == "number"){
8180 if(this.autoBoxAdjust && !this.isBorderBox()){
8181 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8191 * Set the width of the element
8192 * @param {Number} width The new width
8193 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8194 * @return {Roo.Element} this
8196 setWidth : function(width, animate){
8197 width = this.adjustWidth(width);
8199 this.dom.style.width = this.addUnits(width);
8201 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8207 * Set the height of the element
8208 * @param {Number} height The new height
8209 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8210 * @return {Roo.Element} this
8212 setHeight : function(height, animate){
8213 height = this.adjustHeight(height);
8215 this.dom.style.height = this.addUnits(height);
8217 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8223 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8224 * @param {Number} width The new width
8225 * @param {Number} height The new height
8226 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8227 * @return {Roo.Element} this
8229 setSize : function(width, height, animate){
8230 if(typeof width == "object"){ // in case of object from getSize()
8231 height = width.height; width = width.width;
8233 width = this.adjustWidth(width); height = this.adjustHeight(height);
8235 this.dom.style.width = this.addUnits(width);
8236 this.dom.style.height = this.addUnits(height);
8238 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8244 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8245 * @param {Number} x X value for new position (coordinates are page-based)
8246 * @param {Number} y Y value for new position (coordinates are page-based)
8247 * @param {Number} width The new width
8248 * @param {Number} height The new height
8249 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8250 * @return {Roo.Element} this
8252 setBounds : function(x, y, width, height, animate){
8254 this.setSize(width, height);
8255 this.setLocation(x, y);
8257 width = this.adjustWidth(width); height = this.adjustHeight(height);
8258 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8259 this.preanim(arguments, 4), 'motion');
8265 * 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.
8266 * @param {Roo.lib.Region} region The region to fill
8267 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8268 * @return {Roo.Element} this
8270 setRegion : function(region, animate){
8271 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8276 * Appends an event handler
8278 * @param {String} eventName The type of event to append
8279 * @param {Function} fn The method the event invokes
8280 * @param {Object} scope (optional) The scope (this object) of the fn
8281 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8283 addListener : function(eventName, fn, scope, options)
8285 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
8286 this.addListener('touchstart', this.onTapHandler, this);
8289 // we need to handle a special case where dom element is a svg element.
8290 // in this case we do not actua
8295 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
8296 if (typeof(this.listeners[eventName]) == 'undefined') {
8297 this.listeners[eventName] = new Roo.util.Event(this, eventName);
8299 this.listeners[eventName].addListener(fn, scope, options);
8304 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8309 onTapHandler : function(event)
8311 if(!this.tapedTwice) {
8312 this.tapedTwice = true;
8314 setTimeout( function() {
8315 s.tapedTwice = false;
8319 event.preventDefault();
8320 var revent = new MouseEvent('dblclick', {
8326 this.dom.dispatchEvent(revent);
8327 //action on double tap goes below
8332 * Removes an event handler from this element
8333 * @param {String} eventName the type of event to remove
8334 * @param {Function} fn the method the event invokes
8335 * @param {Function} scope (needed for svg fake listeners)
8336 * @return {Roo.Element} this
8338 removeListener : function(eventName, fn, scope){
8339 Roo.EventManager.removeListener(this.dom, eventName, fn);
8340 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
8343 this.listeners[eventName].removeListener(fn, scope);
8348 * Removes all previous added listeners from this element
8349 * @return {Roo.Element} this
8351 removeAllListeners : function(){
8352 E.purgeElement(this.dom);
8353 this.listeners = {};
8357 relayEvent : function(eventName, observable){
8358 this.on(eventName, function(e){
8359 observable.fireEvent(eventName, e);
8365 * Set the opacity of the element
8366 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8367 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8368 * @return {Roo.Element} this
8370 setOpacity : function(opacity, animate){
8372 var s = this.dom.style;
8375 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8376 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8378 s.opacity = opacity;
8381 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8387 * Gets the left X coordinate
8388 * @param {Boolean} local True to get the local css position instead of page coordinate
8391 getLeft : function(local){
8395 return parseInt(this.getStyle("left"), 10) || 0;
8400 * Gets the right X coordinate of the element (element X position + element width)
8401 * @param {Boolean} local True to get the local css position instead of page coordinate
8404 getRight : function(local){
8406 return this.getX() + this.getWidth();
8408 return (this.getLeft(true) + this.getWidth()) || 0;
8413 * Gets the top Y coordinate
8414 * @param {Boolean} local True to get the local css position instead of page coordinate
8417 getTop : function(local) {
8421 return parseInt(this.getStyle("top"), 10) || 0;
8426 * Gets the bottom Y coordinate of the element (element Y position + element height)
8427 * @param {Boolean} local True to get the local css position instead of page coordinate
8430 getBottom : function(local){
8432 return this.getY() + this.getHeight();
8434 return (this.getTop(true) + this.getHeight()) || 0;
8439 * Initializes positioning on this element. If a desired position is not passed, it will make the
8440 * the element positioned relative IF it is not already positioned.
8441 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8442 * @param {Number} zIndex (optional) The zIndex to apply
8443 * @param {Number} x (optional) Set the page X position
8444 * @param {Number} y (optional) Set the page Y position
8446 position : function(pos, zIndex, x, y){
8448 if(this.getStyle('position') == 'static'){
8449 this.setStyle('position', 'relative');
8452 this.setStyle("position", pos);
8455 this.setStyle("z-index", zIndex);
8457 if(x !== undefined && y !== undefined){
8459 }else if(x !== undefined){
8461 }else if(y !== undefined){
8467 * Clear positioning back to the default when the document was loaded
8468 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8469 * @return {Roo.Element} this
8471 clearPositioning : function(value){
8479 "position" : "static"
8485 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8486 * snapshot before performing an update and then restoring the element.
8489 getPositioning : function(){
8490 var l = this.getStyle("left");
8491 var t = this.getStyle("top");
8493 "position" : this.getStyle("position"),
8495 "right" : l ? "" : this.getStyle("right"),
8497 "bottom" : t ? "" : this.getStyle("bottom"),
8498 "z-index" : this.getStyle("z-index")
8503 * Gets the width of the border(s) for the specified side(s)
8504 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8505 * passing lr would get the border (l)eft width + the border (r)ight width.
8506 * @return {Number} The width of the sides passed added together
8508 getBorderWidth : function(side){
8509 return this.addStyles(side, El.borders);
8513 * Gets the width of the padding(s) for the specified side(s)
8514 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8515 * passing lr would get the padding (l)eft + the padding (r)ight.
8516 * @return {Number} The padding of the sides passed added together
8518 getPadding : function(side){
8519 return this.addStyles(side, El.paddings);
8523 * Set positioning with an object returned by getPositioning().
8524 * @param {Object} posCfg
8525 * @return {Roo.Element} this
8527 setPositioning : function(pc){
8528 this.applyStyles(pc);
8529 if(pc.right == "auto"){
8530 this.dom.style.right = "";
8532 if(pc.bottom == "auto"){
8533 this.dom.style.bottom = "";
8539 fixDisplay : function(){
8540 if(this.getStyle("display") == "none"){
8541 this.setStyle("visibility", "hidden");
8542 this.setStyle("display", this.originalDisplay); // first try reverting to default
8543 if(this.getStyle("display") == "none"){ // if that fails, default to block
8544 this.setStyle("display", "block");
8550 * Quick set left and top adding default units
8551 * @param {String} left The left CSS property value
8552 * @param {String} top The top CSS property value
8553 * @return {Roo.Element} this
8555 setLeftTop : function(left, top){
8556 this.dom.style.left = this.addUnits(left);
8557 this.dom.style.top = this.addUnits(top);
8562 * Move this element relative to its current position.
8563 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8564 * @param {Number} distance How far to move the element in pixels
8565 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8566 * @return {Roo.Element} this
8568 move : function(direction, distance, animate){
8569 var xy = this.getXY();
8570 direction = direction.toLowerCase();
8574 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8578 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8583 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8588 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8595 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8596 * @return {Roo.Element} this
8599 if(!this.isClipped){
8600 this.isClipped = true;
8601 this.originalClip = {
8602 "o": this.getStyle("overflow"),
8603 "x": this.getStyle("overflow-x"),
8604 "y": this.getStyle("overflow-y")
8606 this.setStyle("overflow", "hidden");
8607 this.setStyle("overflow-x", "hidden");
8608 this.setStyle("overflow-y", "hidden");
8614 * Return clipping (overflow) to original clipping before clip() was called
8615 * @return {Roo.Element} this
8617 unclip : function(){
8619 this.isClipped = false;
8620 var o = this.originalClip;
8621 if(o.o){this.setStyle("overflow", o.o);}
8622 if(o.x){this.setStyle("overflow-x", o.x);}
8623 if(o.y){this.setStyle("overflow-y", o.y);}
8630 * Gets the x,y coordinates specified by the anchor position on the element.
8631 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8632 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8633 * {width: (target width), height: (target height)} (defaults to the element's current size)
8634 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8635 * @return {Array} [x, y] An array containing the element's x and y coordinates
8637 getAnchorXY : function(anchor, local, s){
8638 //Passing a different size is useful for pre-calculating anchors,
8639 //especially for anchored animations that change the el size.
8641 var w, h, vp = false;
8644 if(d == document.body || d == document){
8646 w = D.getViewWidth(); h = D.getViewHeight();
8648 w = this.getWidth(); h = this.getHeight();
8651 w = s.width; h = s.height;
8653 var x = 0, y = 0, r = Math.round;
8654 switch((anchor || "tl").toLowerCase()){
8696 var sc = this.getScroll();
8697 return [x + sc.left, y + sc.top];
8699 //Add the element's offset xy
8700 var o = this.getXY();
8701 return [x+o[0], y+o[1]];
8705 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8706 * supported position values.
8707 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8708 * @param {String} position The position to align to.
8709 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8710 * @return {Array} [x, y]
8712 getAlignToXY : function(el, p, o)
8717 throw "Element.alignTo with an element that doesn't exist";
8719 var c = false; //constrain to viewport
8720 var p1 = "", p2 = "";
8727 }else if(p.indexOf("-") == -1){
8730 p = p.toLowerCase();
8731 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8733 throw "Element.alignTo with an invalid alignment " + p;
8735 p1 = m[1]; p2 = m[2]; c = !!m[3];
8737 //Subtract the aligned el's internal xy from the target's offset xy
8738 //plus custom offset to get the aligned el's new offset xy
8739 var a1 = this.getAnchorXY(p1, true);
8740 var a2 = el.getAnchorXY(p2, false);
8741 var x = a2[0] - a1[0] + o[0];
8742 var y = a2[1] - a1[1] + o[1];
8744 //constrain the aligned el to viewport if necessary
8745 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8746 // 5px of margin for ie
8747 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8749 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8750 //perpendicular to the vp border, allow the aligned el to slide on that border,
8751 //otherwise swap the aligned el to the opposite border of the target.
8752 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8753 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8754 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8755 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8758 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8759 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8761 if((x+w) > dw + scrollX){
8762 x = swapX ? r.left-w : dw+scrollX-w;
8765 x = swapX ? r.right : scrollX;
8767 if((y+h) > dh + scrollY){
8768 y = swapY ? r.top-h : dh+scrollY-h;
8771 y = swapY ? r.bottom : scrollY;
8778 getConstrainToXY : function(){
8779 var os = {top:0, left:0, bottom:0, right: 0};
8781 return function(el, local, offsets, proposedXY){
8783 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8785 var vw, vh, vx = 0, vy = 0;
8786 if(el.dom == document.body || el.dom == document){
8787 vw = Roo.lib.Dom.getViewWidth();
8788 vh = Roo.lib.Dom.getViewHeight();
8790 vw = el.dom.clientWidth;
8791 vh = el.dom.clientHeight;
8793 var vxy = el.getXY();
8799 var s = el.getScroll();
8801 vx += offsets.left + s.left;
8802 vy += offsets.top + s.top;
8804 vw -= offsets.right;
8805 vh -= offsets.bottom;
8810 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8811 var x = xy[0], y = xy[1];
8812 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8814 // only move it if it needs it
8817 // first validate right/bottom
8826 // then make sure top/left isn't negative
8835 return moved ? [x, y] : false;
8840 adjustForConstraints : function(xy, parent, offsets){
8841 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8845 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8846 * document it aligns it to the viewport.
8847 * The position parameter is optional, and can be specified in any one of the following formats:
8849 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8850 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8851 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8852 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8853 * <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
8854 * element's anchor point, and the second value is used as the target's anchor point.</li>
8856 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8857 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8858 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8859 * that specified in order to enforce the viewport constraints.
8860 * Following are all of the supported anchor positions:
8863 ----- -----------------------------
8864 tl The top left corner (default)
8865 t The center of the top edge
8866 tr The top right corner
8867 l The center of the left edge
8868 c In the center of the element
8869 r The center of the right edge
8870 bl The bottom left corner
8871 b The center of the bottom edge
8872 br The bottom right corner
8876 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8877 el.alignTo("other-el");
8879 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8880 el.alignTo("other-el", "tr?");
8882 // align the bottom right corner of el with the center left edge of other-el
8883 el.alignTo("other-el", "br-l?");
8885 // align the center of el with the bottom left corner of other-el and
8886 // adjust the x position by -6 pixels (and the y position by 0)
8887 el.alignTo("other-el", "c-bl", [-6, 0]);
8889 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8890 * @param {String} position The position to align to.
8891 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8892 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8893 * @return {Roo.Element} this
8895 alignTo : function(element, position, offsets, animate){
8896 var xy = this.getAlignToXY(element, position, offsets);
8897 this.setXY(xy, this.preanim(arguments, 3));
8902 * Anchors an element to another element and realigns it when the window is resized.
8903 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8904 * @param {String} position The position to align to.
8905 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8906 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8907 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8908 * is a number, it is used as the buffer delay (defaults to 50ms).
8909 * @param {Function} callback The function to call after the animation finishes
8910 * @return {Roo.Element} this
8912 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8913 var action = function(){
8914 this.alignTo(el, alignment, offsets, animate);
8915 Roo.callback(callback, this);
8917 Roo.EventManager.onWindowResize(action, this);
8918 var tm = typeof monitorScroll;
8919 if(tm != 'undefined'){
8920 Roo.EventManager.on(window, 'scroll', action, this,
8921 {buffer: tm == 'number' ? monitorScroll : 50});
8923 action.call(this); // align immediately
8927 * Clears any opacity settings from this element. Required in some cases for IE.
8928 * @return {Roo.Element} this
8930 clearOpacity : function(){
8931 if (window.ActiveXObject) {
8932 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8933 this.dom.style.filter = "";
8936 this.dom.style.opacity = "";
8937 this.dom.style["-moz-opacity"] = "";
8938 this.dom.style["-khtml-opacity"] = "";
8944 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8945 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8946 * @return {Roo.Element} this
8948 hide : function(animate){
8949 this.setVisible(false, this.preanim(arguments, 0));
8954 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8955 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8956 * @return {Roo.Element} this
8958 show : function(animate){
8959 this.setVisible(true, this.preanim(arguments, 0));
8964 * @private Test if size has a unit, otherwise appends the default
8966 addUnits : function(size){
8967 return Roo.Element.addUnits(size, this.defaultUnit);
8971 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8972 * @return {Roo.Element} this
8974 beginMeasure : function(){
8976 if(el.offsetWidth || el.offsetHeight){
8977 return this; // offsets work already
8980 var p = this.dom, b = document.body; // start with this element
8981 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8982 var pe = Roo.get(p);
8983 if(pe.getStyle('display') == 'none'){
8984 changed.push({el: p, visibility: pe.getStyle("visibility")});
8985 p.style.visibility = "hidden";
8986 p.style.display = "block";
8990 this._measureChanged = changed;
8996 * Restores displays to before beginMeasure was called
8997 * @return {Roo.Element} this
8999 endMeasure : function(){
9000 var changed = this._measureChanged;
9002 for(var i = 0, len = changed.length; i < len; i++) {
9004 r.el.style.visibility = r.visibility;
9005 r.el.style.display = "none";
9007 this._measureChanged = null;
9013 * Update the innerHTML of this element, optionally searching for and processing scripts
9014 * @param {String} html The new HTML
9015 * @param {Boolean} loadScripts (optional) true to look for and process scripts
9016 * @param {Function} callback For async script loading you can be noticed when the update completes
9017 * @return {Roo.Element} this
9019 update : function(html, loadScripts, callback){
9020 if(typeof html == "undefined"){
9023 if(loadScripts !== true){
9024 this.dom.innerHTML = html;
9025 if(typeof callback == "function"){
9033 html += '<span id="' + id + '"></span>';
9035 E.onAvailable(id, function(){
9036 var hd = document.getElementsByTagName("head")[0];
9037 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9038 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9039 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9042 while(match = re.exec(html)){
9043 var attrs = match[1];
9044 var srcMatch = attrs ? attrs.match(srcRe) : false;
9045 if(srcMatch && srcMatch[2]){
9046 var s = document.createElement("script");
9047 s.src = srcMatch[2];
9048 var typeMatch = attrs.match(typeRe);
9049 if(typeMatch && typeMatch[2]){
9050 s.type = typeMatch[2];
9053 }else if(match[2] && match[2].length > 0){
9054 if(window.execScript) {
9055 window.execScript(match[2]);
9063 window.eval(match[2]);
9067 var el = document.getElementById(id);
9068 if(el){el.parentNode.removeChild(el);}
9069 if(typeof callback == "function"){
9073 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9078 * Direct access to the UpdateManager update() method (takes the same parameters).
9079 * @param {String/Function} url The url for this request or a function to call to get the url
9080 * @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}
9081 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9082 * @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.
9083 * @return {Roo.Element} this
9086 var um = this.getUpdateManager();
9087 um.update.apply(um, arguments);
9092 * Gets this element's UpdateManager
9093 * @return {Roo.UpdateManager} The UpdateManager
9095 getUpdateManager : function(){
9096 if(!this.updateManager){
9097 this.updateManager = new Roo.UpdateManager(this);
9099 return this.updateManager;
9103 * Disables text selection for this element (normalized across browsers)
9104 * @return {Roo.Element} this
9106 unselectable : function(){
9107 this.dom.unselectable = "on";
9108 this.swallowEvent("selectstart", true);
9109 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9110 this.addClass("x-unselectable");
9115 * Calculates the x, y to center this element on the screen
9116 * @return {Array} The x, y values [x, y]
9118 getCenterXY : function(){
9119 return this.getAlignToXY(document, 'c-c');
9123 * Centers the Element in either the viewport, or another Element.
9124 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9126 center : function(centerIn){
9127 this.alignTo(centerIn || document, 'c-c');
9132 * Tests various css rules/browsers to determine if this element uses a border box
9135 isBorderBox : function(){
9136 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9140 * Return a box {x, y, width, height} that can be used to set another elements
9141 * size/location to match this element.
9142 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9143 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9144 * @return {Object} box An object in the format {x, y, width, height}
9146 getBox : function(contentBox, local){
9151 var left = parseInt(this.getStyle("left"), 10) || 0;
9152 var top = parseInt(this.getStyle("top"), 10) || 0;
9155 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9157 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9159 var l = this.getBorderWidth("l")+this.getPadding("l");
9160 var r = this.getBorderWidth("r")+this.getPadding("r");
9161 var t = this.getBorderWidth("t")+this.getPadding("t");
9162 var b = this.getBorderWidth("b")+this.getPadding("b");
9163 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)};
9165 bx.right = bx.x + bx.width;
9166 bx.bottom = bx.y + bx.height;
9171 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9172 for more information about the sides.
9173 * @param {String} sides
9176 getFrameWidth : function(sides, onlyContentBox){
9177 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9181 * 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.
9182 * @param {Object} box The box to fill {x, y, width, height}
9183 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9184 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9185 * @return {Roo.Element} this
9187 setBox : function(box, adjust, animate){
9188 var w = box.width, h = box.height;
9189 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9190 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9191 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9193 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9198 * Forces the browser to repaint this element
9199 * @return {Roo.Element} this
9201 repaint : function(){
9203 this.addClass("x-repaint");
9204 setTimeout(function(){
9205 Roo.get(dom).removeClass("x-repaint");
9211 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9212 * then it returns the calculated width of the sides (see getPadding)
9213 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9214 * @return {Object/Number}
9216 getMargins : function(side){
9219 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9220 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9221 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9222 right: parseInt(this.getStyle("margin-right"), 10) || 0
9225 return this.addStyles(side, El.margins);
9230 addStyles : function(sides, styles){
9232 for(var i = 0, len = sides.length; i < len; i++){
9233 v = this.getStyle(styles[sides.charAt(i)]);
9235 w = parseInt(v, 10);
9243 * Creates a proxy element of this element
9244 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9245 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9246 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9247 * @return {Roo.Element} The new proxy element
9249 createProxy : function(config, renderTo, matchBox){
9251 renderTo = Roo.getDom(renderTo);
9253 renderTo = document.body;
9255 config = typeof config == "object" ?
9256 config : {tag : "div", cls: config};
9257 var proxy = Roo.DomHelper.append(renderTo, config, true);
9259 proxy.setBox(this.getBox());
9265 * Puts a mask over this element to disable user interaction. Requires core.css.
9266 * This method can only be applied to elements which accept child nodes.
9267 * @param {String} msg (optional) A message to display in the mask
9268 * @param {String} msgCls (optional) A css class to apply to the msg element
9269 * @return {Element} The mask element
9271 mask : function(msg, msgCls)
9273 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9274 this.setStyle("position", "relative");
9277 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9280 this.addClass("x-masked");
9281 this._mask.setDisplayed(true);
9286 while (dom && dom.style) {
9287 if (!isNaN(parseInt(dom.style.zIndex))) {
9288 z = Math.max(z, parseInt(dom.style.zIndex));
9290 dom = dom.parentNode;
9292 // if we are masking the body - then it hides everything..
9293 if (this.dom == document.body) {
9295 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9296 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9299 if(typeof msg == 'string'){
9301 this._maskMsg = Roo.DomHelper.append(this.dom, {
9302 cls: "roo-el-mask-msg",
9306 cls: 'fa fa-spinner fa-spin'
9314 var mm = this._maskMsg;
9315 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9316 if (mm.dom.lastChild) { // weird IE issue?
9317 mm.dom.lastChild.innerHTML = msg;
9319 mm.setDisplayed(true);
9321 mm.setStyle('z-index', z + 102);
9323 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9324 this._mask.setHeight(this.getHeight());
9326 this._mask.setStyle('z-index', z + 100);
9332 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9333 * it is cached for reuse.
9335 unmask : function(removeEl){
9337 if(removeEl === true){
9338 this._mask.remove();
9341 this._maskMsg.remove();
9342 delete this._maskMsg;
9345 this._mask.setDisplayed(false);
9347 this._maskMsg.setDisplayed(false);
9351 this.removeClass("x-masked");
9355 * Returns true if this element is masked
9358 isMasked : function(){
9359 return this._mask && this._mask.isVisible();
9363 * Creates an iframe shim for this element to keep selects and other windowed objects from
9365 * @return {Roo.Element} The new shim element
9367 createShim : function(){
9368 var el = document.createElement('iframe');
9369 el.frameBorder = 'no';
9370 el.className = 'roo-shim';
9371 if(Roo.isIE && Roo.isSecure){
9372 el.src = Roo.SSL_SECURE_URL;
9374 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9375 shim.autoBoxAdjust = false;
9380 * Removes this element from the DOM and deletes it from the cache
9382 remove : function(){
9383 if(this.dom.parentNode){
9384 this.dom.parentNode.removeChild(this.dom);
9386 delete El.cache[this.dom.id];
9390 * Sets up event handlers to add and remove a css class when the mouse is over this element
9391 * @param {String} className
9392 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9393 * mouseout events for children elements
9394 * @return {Roo.Element} this
9396 addClassOnOver : function(className, preventFlicker){
9397 this.on("mouseover", function(){
9398 Roo.fly(this, '_internal').addClass(className);
9400 var removeFn = function(e){
9401 if(preventFlicker !== true || !e.within(this, true)){
9402 Roo.fly(this, '_internal').removeClass(className);
9405 this.on("mouseout", removeFn, this.dom);
9410 * Sets up event handlers to add and remove a css class when this element has the focus
9411 * @param {String} className
9412 * @return {Roo.Element} this
9414 addClassOnFocus : function(className){
9415 this.on("focus", function(){
9416 Roo.fly(this, '_internal').addClass(className);
9418 this.on("blur", function(){
9419 Roo.fly(this, '_internal').removeClass(className);
9424 * 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)
9425 * @param {String} className
9426 * @return {Roo.Element} this
9428 addClassOnClick : function(className){
9430 this.on("mousedown", function(){
9431 Roo.fly(dom, '_internal').addClass(className);
9432 var d = Roo.get(document);
9433 var fn = function(){
9434 Roo.fly(dom, '_internal').removeClass(className);
9435 d.removeListener("mouseup", fn);
9437 d.on("mouseup", fn);
9443 * Stops the specified event from bubbling and optionally prevents the default action
9444 * @param {String} eventName
9445 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9446 * @return {Roo.Element} this
9448 swallowEvent : function(eventName, preventDefault){
9449 var fn = function(e){
9450 e.stopPropagation();
9455 if(eventName instanceof Array){
9456 for(var i = 0, len = eventName.length; i < len; i++){
9457 this.on(eventName[i], fn);
9461 this.on(eventName, fn);
9468 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9471 * Sizes this element to its parent element's dimensions performing
9472 * neccessary box adjustments.
9473 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9474 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9475 * @return {Roo.Element} this
9477 fitToParent : function(monitorResize, targetParent) {
9478 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9479 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9480 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9483 var p = Roo.get(targetParent || this.dom.parentNode);
9484 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9485 if (monitorResize === true) {
9486 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9487 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9493 * Gets the next sibling, skipping text nodes
9494 * @return {HTMLElement} The next sibling or null
9496 getNextSibling : function(){
9497 var n = this.dom.nextSibling;
9498 while(n && n.nodeType != 1){
9505 * Gets the previous sibling, skipping text nodes
9506 * @return {HTMLElement} The previous sibling or null
9508 getPrevSibling : function(){
9509 var n = this.dom.previousSibling;
9510 while(n && n.nodeType != 1){
9511 n = n.previousSibling;
9518 * Appends the passed element(s) to this element
9519 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9520 * @return {Roo.Element} this
9522 appendChild: function(el){
9529 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9530 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9531 * automatically generated with the specified attributes.
9532 * @param {HTMLElement} insertBefore (optional) a child element of this element
9533 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9534 * @return {Roo.Element} The new child element
9536 createChild: function(config, insertBefore, returnDom){
9537 config = config || {tag:'div'};
9539 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9541 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9545 * Appends this element to the passed element
9546 * @param {String/HTMLElement/Element} el The new parent element
9547 * @return {Roo.Element} this
9549 appendTo: function(el){
9550 el = Roo.getDom(el);
9551 el.appendChild(this.dom);
9556 * Inserts this element before the passed element in the DOM
9557 * @param {String/HTMLElement/Element} el The element to insert before
9558 * @return {Roo.Element} this
9560 insertBefore: function(el){
9561 el = Roo.getDom(el);
9562 el.parentNode.insertBefore(this.dom, el);
9567 * Inserts this element after the passed element in the DOM
9568 * @param {String/HTMLElement/Element} el The element to insert after
9569 * @return {Roo.Element} this
9571 insertAfter: function(el){
9572 el = Roo.getDom(el);
9573 el.parentNode.insertBefore(this.dom, el.nextSibling);
9578 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9579 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9580 * @return {Roo.Element} The new child
9582 insertFirst: function(el, returnDom){
9584 if(typeof el == 'object' && !el.nodeType){ // dh config
9585 return this.createChild(el, this.dom.firstChild, returnDom);
9587 el = Roo.getDom(el);
9588 this.dom.insertBefore(el, this.dom.firstChild);
9589 return !returnDom ? Roo.get(el) : el;
9594 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9595 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9596 * @param {String} where (optional) 'before' or 'after' defaults to before
9597 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9598 * @return {Roo.Element} the inserted Element
9600 insertSibling: function(el, where, returnDom){
9601 where = where ? where.toLowerCase() : 'before';
9603 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9605 if(typeof el == 'object' && !el.nodeType){ // dh config
9606 if(where == 'after' && !this.dom.nextSibling){
9607 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9609 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9613 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9614 where == 'before' ? this.dom : this.dom.nextSibling);
9623 * Creates and wraps this element with another element
9624 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9625 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9626 * @return {HTMLElement/Element} The newly created wrapper element
9628 wrap: function(config, returnDom){
9630 config = {tag: "div"};
9632 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9633 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9638 * Replaces the passed element with this element
9639 * @param {String/HTMLElement/Element} el The element to replace
9640 * @return {Roo.Element} this
9642 replace: function(el){
9644 this.insertBefore(el);
9650 * Inserts an html fragment into this element
9651 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9652 * @param {String} html The HTML fragment
9653 * @param {Boolean} returnEl True to return an Roo.Element
9654 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9656 insertHtml : function(where, html, returnEl){
9657 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9658 return returnEl ? Roo.get(el) : el;
9662 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9663 * @param {Object} o The object with the attributes
9664 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9665 * @return {Roo.Element} this
9667 set : function(o, useSet){
9669 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9671 if(attr == "style" || typeof o[attr] == "function") { continue; }
9673 el.className = o["cls"];
9676 el.setAttribute(attr, o[attr]);
9683 Roo.DomHelper.applyStyles(el, o.style);
9689 * Convenience method for constructing a KeyMap
9690 * @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:
9691 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9692 * @param {Function} fn The function to call
9693 * @param {Object} scope (optional) The scope of the function
9694 * @return {Roo.KeyMap} The KeyMap created
9696 addKeyListener : function(key, fn, scope){
9698 if(typeof key != "object" || key instanceof Array){
9714 return new Roo.KeyMap(this, config);
9718 * Creates a KeyMap for this element
9719 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9720 * @return {Roo.KeyMap} The KeyMap created
9722 addKeyMap : function(config){
9723 return new Roo.KeyMap(this, config);
9727 * Returns true if this element is scrollable.
9730 isScrollable : function(){
9732 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9736 * 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().
9737 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9738 * @param {Number} value The new scroll value
9739 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9740 * @return {Element} this
9743 scrollTo : function(side, value, animate){
9744 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9746 this.dom[prop] = value;
9748 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9749 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9755 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9756 * within this element's scrollable range.
9757 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9758 * @param {Number} distance How far to scroll the element in pixels
9759 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9760 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9761 * was scrolled as far as it could go.
9763 scroll : function(direction, distance, animate){
9764 if(!this.isScrollable()){
9768 var l = el.scrollLeft, t = el.scrollTop;
9769 var w = el.scrollWidth, h = el.scrollHeight;
9770 var cw = el.clientWidth, ch = el.clientHeight;
9771 direction = direction.toLowerCase();
9772 var scrolled = false;
9773 var a = this.preanim(arguments, 2);
9778 var v = Math.min(l + distance, w-cw);
9779 this.scrollTo("left", v, a);
9786 var v = Math.max(l - distance, 0);
9787 this.scrollTo("left", v, a);
9795 var v = Math.max(t - distance, 0);
9796 this.scrollTo("top", v, a);
9804 var v = Math.min(t + distance, h-ch);
9805 this.scrollTo("top", v, a);
9814 * Translates the passed page coordinates into left/top css values for this element
9815 * @param {Number/Array} x The page x or an array containing [x, y]
9816 * @param {Number} y The page y
9817 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9819 translatePoints : function(x, y){
9820 if(typeof x == 'object' || x instanceof Array){
9823 var p = this.getStyle('position');
9824 var o = this.getXY();
9826 var l = parseInt(this.getStyle('left'), 10);
9827 var t = parseInt(this.getStyle('top'), 10);
9830 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9833 t = (p == "relative") ? 0 : this.dom.offsetTop;
9836 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9840 * Returns the current scroll position of the element.
9841 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9843 getScroll : function(){
9844 var d = this.dom, doc = document;
9845 if(d == doc || d == doc.body){
9846 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9847 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9848 return {left: l, top: t};
9850 return {left: d.scrollLeft, top: d.scrollTop};
9855 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9856 * are convert to standard 6 digit hex color.
9857 * @param {String} attr The css attribute
9858 * @param {String} defaultValue The default value to use when a valid color isn't found
9859 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9862 getColor : function(attr, defaultValue, prefix){
9863 var v = this.getStyle(attr);
9864 if(!v || v == "transparent" || v == "inherit") {
9865 return defaultValue;
9867 var color = typeof prefix == "undefined" ? "#" : prefix;
9868 if(v.substr(0, 4) == "rgb("){
9869 var rvs = v.slice(4, v.length -1).split(",");
9870 for(var i = 0; i < 3; i++){
9871 var h = parseInt(rvs[i]).toString(16);
9878 if(v.substr(0, 1) == "#"){
9880 for(var i = 1; i < 4; i++){
9881 var c = v.charAt(i);
9884 }else if(v.length == 7){
9885 color += v.substr(1);
9889 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9893 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9894 * gradient background, rounded corners and a 4-way shadow.
9895 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9896 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9897 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9898 * @return {Roo.Element} this
9900 boxWrap : function(cls){
9901 cls = cls || 'x-box';
9902 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9903 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9908 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9909 * @param {String} namespace The namespace in which to look for the attribute
9910 * @param {String} name The attribute name
9911 * @return {String} The attribute value
9913 getAttributeNS : Roo.isIE ? function(ns, name){
9915 var type = typeof d[ns+":"+name];
9916 if(type != 'undefined' && type != 'unknown'){
9917 return d[ns+":"+name];
9920 } : function(ns, name){
9922 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9927 * Sets or Returns the value the dom attribute value
9928 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9929 * @param {String} value (optional) The value to set the attribute to
9930 * @return {String} The attribute value
9932 attr : function(name){
9933 if (arguments.length > 1) {
9934 this.dom.setAttribute(name, arguments[1]);
9935 return arguments[1];
9937 if (typeof(name) == 'object') {
9938 for(var i in name) {
9939 this.attr(i, name[i]);
9945 if (!this.dom.hasAttribute(name)) {
9948 return this.dom.getAttribute(name);
9955 var ep = El.prototype;
9958 * Appends an event handler (Shorthand for addListener)
9959 * @param {String} eventName The type of event to append
9960 * @param {Function} fn The method the event invokes
9961 * @param {Object} scope (optional) The scope (this object) of the fn
9962 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9965 ep.on = ep.addListener;
9967 ep.mon = ep.addListener;
9970 * Removes an event handler from this element (shorthand for removeListener)
9971 * @param {String} eventName the type of event to remove
9972 * @param {Function} fn the method the event invokes
9973 * @return {Roo.Element} this
9976 ep.un = ep.removeListener;
9979 * true to automatically adjust width and height settings for box-model issues (default to true)
9981 ep.autoBoxAdjust = true;
9984 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9987 El.addUnits = function(v, defaultUnit){
9988 if(v === "" || v == "auto"){
9991 if(v === undefined){
9994 if(typeof v == "number" || !El.unitPattern.test(v)){
9995 return v + (defaultUnit || 'px');
10000 // special markup used throughout Roo when box wrapping elements
10001 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>';
10003 * Visibility mode constant - Use visibility to hide element
10009 * Visibility mode constant - Use display to hide element
10015 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10016 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10017 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10029 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10030 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10031 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10032 * @return {Element} The Element object
10035 El.get = function(el){
10037 if(!el){ return null; }
10038 if(typeof el == "string"){ // element id
10039 if(!(elm = document.getElementById(el))){
10042 if(ex = El.cache[el]){
10045 ex = El.cache[el] = new El(elm);
10048 }else if(el.tagName){ // dom element
10052 if(ex = El.cache[id]){
10055 ex = El.cache[id] = new El(el);
10058 }else if(el instanceof El){
10060 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10061 // catch case where it hasn't been appended
10062 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10065 }else if(el.isComposite){
10067 }else if(el instanceof Array){
10068 return El.select(el);
10069 }else if(el == document){
10070 // create a bogus element object representing the document object
10072 var f = function(){};
10073 f.prototype = El.prototype;
10075 docEl.dom = document;
10083 El.uncache = function(el){
10084 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10086 delete El.cache[a[i].id || a[i]];
10092 // Garbage collection - uncache elements/purge listeners on orphaned elements
10093 // so we don't hold a reference and cause the browser to retain them
10094 El.garbageCollect = function(){
10095 if(!Roo.enableGarbageCollector){
10096 clearInterval(El.collectorThread);
10099 for(var eid in El.cache){
10100 var el = El.cache[eid], d = el.dom;
10101 // -------------------------------------------------------
10102 // Determining what is garbage:
10103 // -------------------------------------------------------
10105 // dom node is null, definitely garbage
10106 // -------------------------------------------------------
10108 // no parentNode == direct orphan, definitely garbage
10109 // -------------------------------------------------------
10110 // !d.offsetParent && !document.getElementById(eid)
10111 // display none elements have no offsetParent so we will
10112 // also try to look it up by it's id. However, check
10113 // offsetParent first so we don't do unneeded lookups.
10114 // This enables collection of elements that are not orphans
10115 // directly, but somewhere up the line they have an orphan
10117 // -------------------------------------------------------
10118 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10119 delete El.cache[eid];
10120 if(d && Roo.enableListenerCollection){
10126 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10130 El.Flyweight = function(dom){
10133 El.Flyweight.prototype = El.prototype;
10135 El._flyweights = {};
10137 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10138 * the dom node can be overwritten by other code.
10139 * @param {String/HTMLElement} el The dom node or id
10140 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10141 * prevent conflicts (e.g. internally Roo uses "_internal")
10143 * @return {Element} The shared Element object
10145 El.fly = function(el, named){
10146 named = named || '_global';
10147 el = Roo.getDom(el);
10151 if(!El._flyweights[named]){
10152 El._flyweights[named] = new El.Flyweight();
10154 El._flyweights[named].dom = el;
10155 return El._flyweights[named];
10159 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10160 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10161 * Shorthand of {@link Roo.Element#get}
10162 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10163 * @return {Element} The Element object
10169 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10170 * the dom node can be overwritten by other code.
10171 * Shorthand of {@link Roo.Element#fly}
10172 * @param {String/HTMLElement} el The dom node or id
10173 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10174 * prevent conflicts (e.g. internally Roo uses "_internal")
10176 * @return {Element} The shared Element object
10182 // speedy lookup for elements never to box adjust
10183 var noBoxAdjust = Roo.isStrict ? {
10186 input:1, select:1, textarea:1
10188 if(Roo.isIE || Roo.isGecko){
10189 noBoxAdjust['button'] = 1;
10193 Roo.EventManager.on(window, 'unload', function(){
10195 delete El._flyweights;
10203 Roo.Element.selectorFunction = Roo.DomQuery.select;
10206 Roo.Element.select = function(selector, unique, root){
10208 if(typeof selector == "string"){
10209 els = Roo.Element.selectorFunction(selector, root);
10210 }else if(selector.length !== undefined){
10213 throw "Invalid selector";
10215 if(unique === true){
10216 return new Roo.CompositeElement(els);
10218 return new Roo.CompositeElementLite(els);
10222 * Selects elements based on the passed CSS selector to enable working on them as 1.
10223 * @param {String/Array} selector The CSS selector or an array of elements
10224 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10225 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10226 * @return {CompositeElementLite/CompositeElement}
10230 Roo.select = Roo.Element.select;
10247 * Ext JS Library 1.1.1
10248 * Copyright(c) 2006-2007, Ext JS, LLC.
10250 * Originally Released Under LGPL - original licence link has changed is not relivant.
10253 * <script type="text/javascript">
10258 //Notifies Element that fx methods are available
10259 Roo.enableFx = true;
10263 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10264 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10265 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10266 * Element effects to work.</p><br/>
10268 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10269 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10270 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10271 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10272 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10273 * expected results and should be done with care.</p><br/>
10275 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10276 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10279 ----- -----------------------------
10280 tl The top left corner
10281 t The center of the top edge
10282 tr The top right corner
10283 l The center of the left edge
10284 r The center of the right edge
10285 bl The bottom left corner
10286 b The center of the bottom edge
10287 br The bottom right corner
10289 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10290 * below are common options that can be passed to any Fx method.</b>
10291 * @cfg {Function} callback A function called when the effect is finished
10292 * @cfg {Object} scope The scope of the effect function
10293 * @cfg {String} easing A valid Easing value for the effect
10294 * @cfg {String} afterCls A css class to apply after the effect
10295 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10296 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10297 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10298 * effects that end with the element being visually hidden, ignored otherwise)
10299 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10300 * a function which returns such a specification that will be applied to the Element after the effect finishes
10301 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10302 * @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
10303 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10307 * Slides the element into view. An anchor point can be optionally passed to set the point of
10308 * origin for the slide effect. This function automatically handles wrapping the element with
10309 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10312 // default: slide the element in from the top
10315 // custom: slide the element in from the right with a 2-second duration
10316 el.slideIn('r', { duration: 2 });
10318 // common config options shown with default values
10324 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10325 * @param {Object} options (optional) Object literal with any of the Fx config options
10326 * @return {Roo.Element} The Element
10328 slideIn : function(anchor, o){
10329 var el = this.getFxEl();
10332 el.queueFx(o, function(){
10334 anchor = anchor || "t";
10336 // fix display to visibility
10339 // restore values after effect
10340 var r = this.getFxRestore();
10341 var b = this.getBox();
10342 // fixed size for slide
10346 var wrap = this.fxWrap(r.pos, o, "hidden");
10348 var st = this.dom.style;
10349 st.visibility = "visible";
10350 st.position = "absolute";
10352 // clear out temp styles after slide and unwrap
10353 var after = function(){
10354 el.fxUnwrap(wrap, r.pos, o);
10355 st.width = r.width;
10356 st.height = r.height;
10359 // time to calc the positions
10360 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10362 switch(anchor.toLowerCase()){
10364 wrap.setSize(b.width, 0);
10365 st.left = st.bottom = "0";
10369 wrap.setSize(0, b.height);
10370 st.right = st.top = "0";
10374 wrap.setSize(0, b.height);
10375 wrap.setX(b.right);
10376 st.left = st.top = "0";
10377 a = {width: bw, points: pt};
10380 wrap.setSize(b.width, 0);
10381 wrap.setY(b.bottom);
10382 st.left = st.top = "0";
10383 a = {height: bh, points: pt};
10386 wrap.setSize(0, 0);
10387 st.right = st.bottom = "0";
10388 a = {width: bw, height: bh};
10391 wrap.setSize(0, 0);
10392 wrap.setY(b.y+b.height);
10393 st.right = st.top = "0";
10394 a = {width: bw, height: bh, points: pt};
10397 wrap.setSize(0, 0);
10398 wrap.setXY([b.right, b.bottom]);
10399 st.left = st.top = "0";
10400 a = {width: bw, height: bh, points: pt};
10403 wrap.setSize(0, 0);
10404 wrap.setX(b.x+b.width);
10405 st.left = st.bottom = "0";
10406 a = {width: bw, height: bh, points: pt};
10409 this.dom.style.visibility = "visible";
10412 arguments.callee.anim = wrap.fxanim(a,
10422 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10423 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10424 * 'hidden') but block elements will still take up space in the document. The element must be removed
10425 * from the DOM using the 'remove' config option if desired. This function automatically handles
10426 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10429 // default: slide the element out to the top
10432 // custom: slide the element out to the right with a 2-second duration
10433 el.slideOut('r', { duration: 2 });
10435 // common config options shown with default values
10443 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10444 * @param {Object} options (optional) Object literal with any of the Fx config options
10445 * @return {Roo.Element} The Element
10447 slideOut : function(anchor, o){
10448 var el = this.getFxEl();
10451 el.queueFx(o, function(){
10453 anchor = anchor || "t";
10455 // restore values after effect
10456 var r = this.getFxRestore();
10458 var b = this.getBox();
10459 // fixed size for slide
10463 var wrap = this.fxWrap(r.pos, o, "visible");
10465 var st = this.dom.style;
10466 st.visibility = "visible";
10467 st.position = "absolute";
10471 var after = function(){
10473 el.setDisplayed(false);
10478 el.fxUnwrap(wrap, r.pos, o);
10480 st.width = r.width;
10481 st.height = r.height;
10486 var a, zero = {to: 0};
10487 switch(anchor.toLowerCase()){
10489 st.left = st.bottom = "0";
10490 a = {height: zero};
10493 st.right = st.top = "0";
10497 st.left = st.top = "0";
10498 a = {width: zero, points: {to:[b.right, b.y]}};
10501 st.left = st.top = "0";
10502 a = {height: zero, points: {to:[b.x, b.bottom]}};
10505 st.right = st.bottom = "0";
10506 a = {width: zero, height: zero};
10509 st.right = st.top = "0";
10510 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10513 st.left = st.top = "0";
10514 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10517 st.left = st.bottom = "0";
10518 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10522 arguments.callee.anim = wrap.fxanim(a,
10532 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10533 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10534 * The element must be removed from the DOM using the 'remove' config option if desired.
10540 // common config options shown with default values
10548 * @param {Object} options (optional) Object literal with any of the Fx config options
10549 * @return {Roo.Element} The Element
10551 puff : function(o){
10552 var el = this.getFxEl();
10555 el.queueFx(o, function(){
10556 this.clearOpacity();
10559 // restore values after effect
10560 var r = this.getFxRestore();
10561 var st = this.dom.style;
10563 var after = function(){
10565 el.setDisplayed(false);
10572 el.setPositioning(r.pos);
10573 st.width = r.width;
10574 st.height = r.height;
10579 var width = this.getWidth();
10580 var height = this.getHeight();
10582 arguments.callee.anim = this.fxanim({
10583 width : {to: this.adjustWidth(width * 2)},
10584 height : {to: this.adjustHeight(height * 2)},
10585 points : {by: [-(width * .5), -(height * .5)]},
10587 fontSize: {to:200, unit: "%"}
10598 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10599 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10600 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10606 // all config options shown with default values
10614 * @param {Object} options (optional) Object literal with any of the Fx config options
10615 * @return {Roo.Element} The Element
10617 switchOff : function(o){
10618 var el = this.getFxEl();
10621 el.queueFx(o, function(){
10622 this.clearOpacity();
10625 // restore values after effect
10626 var r = this.getFxRestore();
10627 var st = this.dom.style;
10629 var after = function(){
10631 el.setDisplayed(false);
10637 el.setPositioning(r.pos);
10638 st.width = r.width;
10639 st.height = r.height;
10644 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10645 this.clearOpacity();
10649 points:{by:[0, this.getHeight() * .5]}
10650 }, o, 'motion', 0.3, 'easeIn', after);
10651 }).defer(100, this);
10658 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10659 * changed using the "attr" config option) and then fading back to the original color. If no original
10660 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10663 // default: highlight background to yellow
10666 // custom: highlight foreground text to blue for 2 seconds
10667 el.highlight("0000ff", { attr: 'color', duration: 2 });
10669 // common config options shown with default values
10670 el.highlight("ffff9c", {
10671 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10672 endColor: (current color) or "ffffff",
10677 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10678 * @param {Object} options (optional) Object literal with any of the Fx config options
10679 * @return {Roo.Element} The Element
10681 highlight : function(color, o){
10682 var el = this.getFxEl();
10685 el.queueFx(o, function(){
10686 color = color || "ffff9c";
10687 attr = o.attr || "backgroundColor";
10689 this.clearOpacity();
10692 var origColor = this.getColor(attr);
10693 var restoreColor = this.dom.style[attr];
10694 endColor = (o.endColor || origColor) || "ffffff";
10696 var after = function(){
10697 el.dom.style[attr] = restoreColor;
10702 a[attr] = {from: color, to: endColor};
10703 arguments.callee.anim = this.fxanim(a,
10713 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10716 // default: a single light blue ripple
10719 // custom: 3 red ripples lasting 3 seconds total
10720 el.frame("ff0000", 3, { duration: 3 });
10722 // common config options shown with default values
10723 el.frame("C3DAF9", 1, {
10724 duration: 1 //duration of entire animation (not each individual ripple)
10725 // Note: Easing is not configurable and will be ignored if included
10728 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10729 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10730 * @param {Object} options (optional) Object literal with any of the Fx config options
10731 * @return {Roo.Element} The Element
10733 frame : function(color, count, o){
10734 var el = this.getFxEl();
10737 el.queueFx(o, function(){
10738 color = color || "#C3DAF9";
10739 if(color.length == 6){
10740 color = "#" + color;
10742 count = count || 1;
10743 duration = o.duration || 1;
10746 var b = this.getBox();
10747 var animFn = function(){
10748 var proxy = this.createProxy({
10751 visbility:"hidden",
10752 position:"absolute",
10753 "z-index":"35000", // yee haw
10754 border:"0px solid " + color
10757 var scale = Roo.isBorderBox ? 2 : 1;
10759 top:{from:b.y, to:b.y - 20},
10760 left:{from:b.x, to:b.x - 20},
10761 borderWidth:{from:0, to:10},
10762 opacity:{from:1, to:0},
10763 height:{from:b.height, to:(b.height + (20*scale))},
10764 width:{from:b.width, to:(b.width + (20*scale))}
10765 }, duration, function(){
10769 animFn.defer((duration/2)*1000, this);
10780 * Creates a pause before any subsequent queued effects begin. If there are
10781 * no effects queued after the pause it will have no effect.
10786 * @param {Number} seconds The length of time to pause (in seconds)
10787 * @return {Roo.Element} The Element
10789 pause : function(seconds){
10790 var el = this.getFxEl();
10793 el.queueFx(o, function(){
10794 setTimeout(function(){
10796 }, seconds * 1000);
10802 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10803 * using the "endOpacity" config option.
10806 // default: fade in from opacity 0 to 100%
10809 // custom: fade in from opacity 0 to 75% over 2 seconds
10810 el.fadeIn({ endOpacity: .75, duration: 2});
10812 // common config options shown with default values
10814 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10819 * @param {Object} options (optional) Object literal with any of the Fx config options
10820 * @return {Roo.Element} The Element
10822 fadeIn : function(o){
10823 var el = this.getFxEl();
10825 el.queueFx(o, function(){
10826 this.setOpacity(0);
10828 this.dom.style.visibility = 'visible';
10829 var to = o.endOpacity || 1;
10830 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10831 o, null, .5, "easeOut", function(){
10833 this.clearOpacity();
10842 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10843 * using the "endOpacity" config option.
10846 // default: fade out from the element's current opacity to 0
10849 // custom: fade out from the element's current opacity to 25% over 2 seconds
10850 el.fadeOut({ endOpacity: .25, duration: 2});
10852 // common config options shown with default values
10854 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10861 * @param {Object} options (optional) Object literal with any of the Fx config options
10862 * @return {Roo.Element} The Element
10864 fadeOut : function(o){
10865 var el = this.getFxEl();
10867 el.queueFx(o, function(){
10868 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10869 o, null, .5, "easeOut", function(){
10870 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10871 this.dom.style.display = "none";
10873 this.dom.style.visibility = "hidden";
10875 this.clearOpacity();
10883 * Animates the transition of an element's dimensions from a starting height/width
10884 * to an ending height/width.
10887 // change height and width to 100x100 pixels
10888 el.scale(100, 100);
10890 // common config options shown with default values. The height and width will default to
10891 // the element's existing values if passed as null.
10894 [element's height], {
10899 * @param {Number} width The new width (pass undefined to keep the original width)
10900 * @param {Number} height The new height (pass undefined to keep the original height)
10901 * @param {Object} options (optional) Object literal with any of the Fx config options
10902 * @return {Roo.Element} The Element
10904 scale : function(w, h, o){
10905 this.shift(Roo.apply({}, o, {
10913 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10914 * Any of these properties not specified in the config object will not be changed. This effect
10915 * requires that at least one new dimension, position or opacity setting must be passed in on
10916 * the config object in order for the function to have any effect.
10919 // slide the element horizontally to x position 200 while changing the height and opacity
10920 el.shift({ x: 200, height: 50, opacity: .8 });
10922 // common config options shown with default values.
10924 width: [element's width],
10925 height: [element's height],
10926 x: [element's x position],
10927 y: [element's y position],
10928 opacity: [element's opacity],
10933 * @param {Object} options Object literal with any of the Fx config options
10934 * @return {Roo.Element} The Element
10936 shift : function(o){
10937 var el = this.getFxEl();
10939 el.queueFx(o, function(){
10940 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10941 if(w !== undefined){
10942 a.width = {to: this.adjustWidth(w)};
10944 if(h !== undefined){
10945 a.height = {to: this.adjustHeight(h)};
10947 if(x !== undefined || y !== undefined){
10949 x !== undefined ? x : this.getX(),
10950 y !== undefined ? y : this.getY()
10953 if(op !== undefined){
10954 a.opacity = {to: op};
10956 if(o.xy !== undefined){
10957 a.points = {to: o.xy};
10959 arguments.callee.anim = this.fxanim(a,
10960 o, 'motion', .35, "easeOut", function(){
10968 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10969 * ending point of the effect.
10972 // default: slide the element downward while fading out
10975 // custom: slide the element out to the right with a 2-second duration
10976 el.ghost('r', { duration: 2 });
10978 // common config options shown with default values
10986 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10987 * @param {Object} options (optional) Object literal with any of the Fx config options
10988 * @return {Roo.Element} The Element
10990 ghost : function(anchor, o){
10991 var el = this.getFxEl();
10994 el.queueFx(o, function(){
10995 anchor = anchor || "b";
10997 // restore values after effect
10998 var r = this.getFxRestore();
10999 var w = this.getWidth(),
11000 h = this.getHeight();
11002 var st = this.dom.style;
11004 var after = function(){
11006 el.setDisplayed(false);
11012 el.setPositioning(r.pos);
11013 st.width = r.width;
11014 st.height = r.height;
11019 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11020 switch(anchor.toLowerCase()){
11047 arguments.callee.anim = this.fxanim(a,
11057 * Ensures that all effects queued after syncFx is called on the element are
11058 * run concurrently. This is the opposite of {@link #sequenceFx}.
11059 * @return {Roo.Element} The Element
11061 syncFx : function(){
11062 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11071 * Ensures that all effects queued after sequenceFx is called on the element are
11072 * run in sequence. This is the opposite of {@link #syncFx}.
11073 * @return {Roo.Element} The Element
11075 sequenceFx : function(){
11076 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11078 concurrent : false,
11085 nextFx : function(){
11086 var ef = this.fxQueue[0];
11093 * Returns true if the element has any effects actively running or queued, else returns false.
11094 * @return {Boolean} True if element has active effects, else false
11096 hasActiveFx : function(){
11097 return this.fxQueue && this.fxQueue[0];
11101 * Stops any running effects and clears the element's internal effects queue if it contains
11102 * any additional effects that haven't started yet.
11103 * @return {Roo.Element} The Element
11105 stopFx : function(){
11106 if(this.hasActiveFx()){
11107 var cur = this.fxQueue[0];
11108 if(cur && cur.anim && cur.anim.isAnimated()){
11109 this.fxQueue = [cur]; // clear out others
11110 cur.anim.stop(true);
11117 beforeFx : function(o){
11118 if(this.hasActiveFx() && !o.concurrent){
11129 * Returns true if the element is currently blocking so that no other effect can be queued
11130 * until this effect is finished, else returns false if blocking is not set. This is commonly
11131 * used to ensure that an effect initiated by a user action runs to completion prior to the
11132 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11133 * @return {Boolean} True if blocking, else false
11135 hasFxBlock : function(){
11136 var q = this.fxQueue;
11137 return q && q[0] && q[0].block;
11141 queueFx : function(o, fn){
11145 if(!this.hasFxBlock()){
11146 Roo.applyIf(o, this.fxDefaults);
11148 var run = this.beforeFx(o);
11149 fn.block = o.block;
11150 this.fxQueue.push(fn);
11162 fxWrap : function(pos, o, vis){
11164 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11167 wrapXY = this.getXY();
11169 var div = document.createElement("div");
11170 div.style.visibility = vis;
11171 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11172 wrap.setPositioning(pos);
11173 if(wrap.getStyle("position") == "static"){
11174 wrap.position("relative");
11176 this.clearPositioning('auto');
11178 wrap.dom.appendChild(this.dom);
11180 wrap.setXY(wrapXY);
11187 fxUnwrap : function(wrap, pos, o){
11188 this.clearPositioning();
11189 this.setPositioning(pos);
11191 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11197 getFxRestore : function(){
11198 var st = this.dom.style;
11199 return {pos: this.getPositioning(), width: st.width, height : st.height};
11203 afterFx : function(o){
11205 this.applyStyles(o.afterStyle);
11208 this.addClass(o.afterCls);
11210 if(o.remove === true){
11213 Roo.callback(o.callback, o.scope, [this]);
11215 this.fxQueue.shift();
11221 getFxEl : function(){ // support for composite element fx
11222 return Roo.get(this.dom);
11226 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11227 animType = animType || 'run';
11229 var anim = Roo.lib.Anim[animType](
11231 (opt.duration || defaultDur) || .35,
11232 (opt.easing || defaultEase) || 'easeOut',
11234 Roo.callback(cb, this);
11243 // backwords compat
11244 Roo.Fx.resize = Roo.Fx.scale;
11246 //When included, Roo.Fx is automatically applied to Element so that all basic
11247 //effects are available directly via the Element API
11248 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11250 * Ext JS Library 1.1.1
11251 * Copyright(c) 2006-2007, Ext JS, LLC.
11253 * Originally Released Under LGPL - original licence link has changed is not relivant.
11256 * <script type="text/javascript">
11261 * @class Roo.CompositeElement
11262 * Standard composite class. Creates a Roo.Element for every element in the collection.
11264 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11265 * actions will be performed on all the elements in this collection.</b>
11267 * All methods return <i>this</i> and can be chained.
11269 var els = Roo.select("#some-el div.some-class", true);
11270 // or select directly from an existing element
11271 var el = Roo.get('some-el');
11272 el.select('div.some-class', true);
11274 els.setWidth(100); // all elements become 100 width
11275 els.hide(true); // all elements fade out and hide
11277 els.setWidth(100).hide(true);
11280 Roo.CompositeElement = function(els){
11281 this.elements = [];
11282 this.addElements(els);
11284 Roo.CompositeElement.prototype = {
11286 addElements : function(els){
11290 if(typeof els == "string"){
11291 els = Roo.Element.selectorFunction(els);
11293 var yels = this.elements;
11294 var index = yels.length-1;
11295 for(var i = 0, len = els.length; i < len; i++) {
11296 yels[++index] = Roo.get(els[i]);
11302 * Clears this composite and adds the elements returned by the passed selector.
11303 * @param {String/Array} els A string CSS selector, an array of elements or an element
11304 * @return {CompositeElement} this
11306 fill : function(els){
11307 this.elements = [];
11313 * Filters this composite to only elements that match the passed selector.
11314 * @param {String} selector A string CSS selector
11315 * @param {Boolean} inverse return inverse filter (not matches)
11316 * @return {CompositeElement} this
11318 filter : function(selector, inverse){
11320 inverse = inverse || false;
11321 this.each(function(el){
11322 var match = inverse ? !el.is(selector) : el.is(selector);
11324 els[els.length] = el.dom;
11331 invoke : function(fn, args){
11332 var els = this.elements;
11333 for(var i = 0, len = els.length; i < len; i++) {
11334 Roo.Element.prototype[fn].apply(els[i], args);
11339 * Adds elements to this composite.
11340 * @param {String/Array} els A string CSS selector, an array of elements or an element
11341 * @return {CompositeElement} this
11343 add : function(els){
11344 if(typeof els == "string"){
11345 this.addElements(Roo.Element.selectorFunction(els));
11346 }else if(els.length !== undefined){
11347 this.addElements(els);
11349 this.addElements([els]);
11354 * Calls the passed function passing (el, this, index) for each element in this composite.
11355 * @param {Function} fn The function to call
11356 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11357 * @return {CompositeElement} this
11359 each : function(fn, scope){
11360 var els = this.elements;
11361 for(var i = 0, len = els.length; i < len; i++){
11362 if(fn.call(scope || els[i], els[i], this, i) === false) {
11370 * Returns the Element object at the specified index
11371 * @param {Number} index
11372 * @return {Roo.Element}
11374 item : function(index){
11375 return this.elements[index] || null;
11379 * Returns the first Element
11380 * @return {Roo.Element}
11382 first : function(){
11383 return this.item(0);
11387 * Returns the last Element
11388 * @return {Roo.Element}
11391 return this.item(this.elements.length-1);
11395 * Returns the number of elements in this composite
11398 getCount : function(){
11399 return this.elements.length;
11403 * Returns true if this composite contains the passed element
11406 contains : function(el){
11407 return this.indexOf(el) !== -1;
11411 * Returns true if this composite contains the passed element
11414 indexOf : function(el){
11415 return this.elements.indexOf(Roo.get(el));
11420 * Removes the specified element(s).
11421 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11422 * or an array of any of those.
11423 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11424 * @return {CompositeElement} this
11426 removeElement : function(el, removeDom){
11427 if(el instanceof Array){
11428 for(var i = 0, len = el.length; i < len; i++){
11429 this.removeElement(el[i]);
11433 var index = typeof el == 'number' ? el : this.indexOf(el);
11436 var d = this.elements[index];
11440 d.parentNode.removeChild(d);
11443 this.elements.splice(index, 1);
11449 * Replaces the specified element with the passed element.
11450 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11452 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11453 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11454 * @return {CompositeElement} this
11456 replaceElement : function(el, replacement, domReplace){
11457 var index = typeof el == 'number' ? el : this.indexOf(el);
11460 this.elements[index].replaceWith(replacement);
11462 this.elements.splice(index, 1, Roo.get(replacement))
11469 * Removes all elements.
11471 clear : function(){
11472 this.elements = [];
11476 Roo.CompositeElement.createCall = function(proto, fnName){
11477 if(!proto[fnName]){
11478 proto[fnName] = function(){
11479 return this.invoke(fnName, arguments);
11483 for(var fnName in Roo.Element.prototype){
11484 if(typeof Roo.Element.prototype[fnName] == "function"){
11485 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11491 * Ext JS Library 1.1.1
11492 * Copyright(c) 2006-2007, Ext JS, LLC.
11494 * Originally Released Under LGPL - original licence link has changed is not relivant.
11497 * <script type="text/javascript">
11501 * @class Roo.CompositeElementLite
11502 * @extends Roo.CompositeElement
11503 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11505 var els = Roo.select("#some-el div.some-class");
11506 // or select directly from an existing element
11507 var el = Roo.get('some-el');
11508 el.select('div.some-class');
11510 els.setWidth(100); // all elements become 100 width
11511 els.hide(true); // all elements fade out and hide
11513 els.setWidth(100).hide(true);
11514 </code></pre><br><br>
11515 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11516 * actions will be performed on all the elements in this collection.</b>
11518 Roo.CompositeElementLite = function(els){
11519 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11520 this.el = new Roo.Element.Flyweight();
11522 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11523 addElements : function(els){
11525 if(els instanceof Array){
11526 this.elements = this.elements.concat(els);
11528 var yels = this.elements;
11529 var index = yels.length-1;
11530 for(var i = 0, len = els.length; i < len; i++) {
11531 yels[++index] = els[i];
11537 invoke : function(fn, args){
11538 var els = this.elements;
11540 for(var i = 0, len = els.length; i < len; i++) {
11542 Roo.Element.prototype[fn].apply(el, args);
11547 * Returns a flyweight Element of the dom element object at the specified index
11548 * @param {Number} index
11549 * @return {Roo.Element}
11551 item : function(index){
11552 if(!this.elements[index]){
11555 this.el.dom = this.elements[index];
11559 // fixes scope with flyweight
11560 addListener : function(eventName, handler, scope, opt){
11561 var els = this.elements;
11562 for(var i = 0, len = els.length; i < len; i++) {
11563 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11569 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11570 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11571 * a reference to the dom node, use el.dom.</b>
11572 * @param {Function} fn The function to call
11573 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11574 * @return {CompositeElement} this
11576 each : function(fn, scope){
11577 var els = this.elements;
11579 for(var i = 0, len = els.length; i < len; i++){
11581 if(fn.call(scope || el, el, this, i) === false){
11588 indexOf : function(el){
11589 return this.elements.indexOf(Roo.getDom(el));
11592 replaceElement : function(el, replacement, domReplace){
11593 var index = typeof el == 'number' ? el : this.indexOf(el);
11595 replacement = Roo.getDom(replacement);
11597 var d = this.elements[index];
11598 d.parentNode.insertBefore(replacement, d);
11599 d.parentNode.removeChild(d);
11601 this.elements.splice(index, 1, replacement);
11606 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11610 * Ext JS Library 1.1.1
11611 * Copyright(c) 2006-2007, Ext JS, LLC.
11613 * Originally Released Under LGPL - original licence link has changed is not relivant.
11616 * <script type="text/javascript">
11622 * @class Roo.data.Connection
11623 * @extends Roo.util.Observable
11624 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11625 * either to a configured URL, or to a URL specified at request time.
11627 * Requests made by this class are asynchronous, and will return immediately. No data from
11628 * the server will be available to the statement immediately following the {@link #request} call.
11629 * To process returned data, use a callback in the request options object, or an event listener.
11631 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11632 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11633 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11634 * property and, if present, the IFRAME's XML document as the responseXML property.
11636 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11637 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11638 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11639 * standard DOM methods.
11641 * @param {Object} config a configuration object.
11643 Roo.data.Connection = function(config){
11644 Roo.apply(this, config);
11647 * @event beforerequest
11648 * Fires before a network request is made to retrieve a data object.
11649 * @param {Connection} conn This Connection object.
11650 * @param {Object} options The options config object passed to the {@link #request} method.
11652 "beforerequest" : true,
11654 * @event requestcomplete
11655 * Fires if the request was successfully completed.
11656 * @param {Connection} conn This Connection object.
11657 * @param {Object} response The XHR object containing the response data.
11658 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11659 * @param {Object} options The options config object passed to the {@link #request} method.
11661 "requestcomplete" : true,
11663 * @event requestexception
11664 * Fires if an error HTTP status was returned from the server.
11665 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11666 * @param {Connection} conn This Connection object.
11667 * @param {Object} response The XHR object containing the response data.
11668 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11669 * @param {Object} options The options config object passed to the {@link #request} method.
11671 "requestexception" : true
11673 Roo.data.Connection.superclass.constructor.call(this);
11676 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11678 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11681 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11682 * extra parameters to each request made by this object. (defaults to undefined)
11685 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11686 * to each request made by this object. (defaults to undefined)
11689 * @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)
11692 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11696 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11702 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11705 disableCaching: true,
11708 * Sends an HTTP request to a remote server.
11709 * @param {Object} options An object which may contain the following properties:<ul>
11710 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11711 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11712 * request, a url encoded string or a function to call to get either.</li>
11713 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11714 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11715 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11716 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11717 * <li>options {Object} The parameter to the request call.</li>
11718 * <li>success {Boolean} True if the request succeeded.</li>
11719 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11721 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11722 * The callback is passed the following parameters:<ul>
11723 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11724 * <li>options {Object} The parameter to the request call.</li>
11726 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11727 * The callback is passed the following parameters:<ul>
11728 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11729 * <li>options {Object} The parameter to the request call.</li>
11731 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11732 * for the callback function. Defaults to the browser window.</li>
11733 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11734 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11735 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11736 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11737 * params for the post data. Any params will be appended to the URL.</li>
11738 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11740 * @return {Number} transactionId
11742 request : function(o){
11743 if(this.fireEvent("beforerequest", this, o) !== false){
11746 if(typeof p == "function"){
11747 p = p.call(o.scope||window, o);
11749 if(typeof p == "object"){
11750 p = Roo.urlEncode(o.params);
11752 if(this.extraParams){
11753 var extras = Roo.urlEncode(this.extraParams);
11754 p = p ? (p + '&' + extras) : extras;
11757 var url = o.url || this.url;
11758 if(typeof url == 'function'){
11759 url = url.call(o.scope||window, o);
11763 var form = Roo.getDom(o.form);
11764 url = url || form.action;
11766 var enctype = form.getAttribute("enctype");
11769 return this.doFormDataUpload(o, url);
11772 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11773 return this.doFormUpload(o, p, url);
11775 var f = Roo.lib.Ajax.serializeForm(form);
11776 p = p ? (p + '&' + f) : f;
11779 if (!o.form && o.formData) {
11780 o.formData = o.formData === true ? new FormData() : o.formData;
11781 for (var k in o.params) {
11782 o.formData.append(k,o.params[k]);
11785 return this.doFormDataUpload(o, url);
11789 var hs = o.headers;
11790 if(this.defaultHeaders){
11791 hs = Roo.apply(hs || {}, this.defaultHeaders);
11798 success: this.handleResponse,
11799 failure: this.handleFailure,
11801 argument: {options: o},
11802 timeout : o.timeout || this.timeout
11805 var method = o.method||this.method||(p ? "POST" : "GET");
11807 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11808 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11811 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11815 }else if(this.autoAbort !== false){
11819 if((method == 'GET' && p) || o.xmlData){
11820 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11823 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11824 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11825 Roo.lib.Ajax.useDefaultHeader == true;
11826 return this.transId;
11828 Roo.callback(o.callback, o.scope, [o, null, null]);
11834 * Determine whether this object has a request outstanding.
11835 * @param {Number} transactionId (Optional) defaults to the last transaction
11836 * @return {Boolean} True if there is an outstanding request.
11838 isLoading : function(transId){
11840 return Roo.lib.Ajax.isCallInProgress(transId);
11842 return this.transId ? true : false;
11847 * Aborts any outstanding request.
11848 * @param {Number} transactionId (Optional) defaults to the last transaction
11850 abort : function(transId){
11851 if(transId || this.isLoading()){
11852 Roo.lib.Ajax.abort(transId || this.transId);
11857 handleResponse : function(response){
11858 this.transId = false;
11859 var options = response.argument.options;
11860 response.argument = options ? options.argument : null;
11861 this.fireEvent("requestcomplete", this, response, options);
11862 Roo.callback(options.success, options.scope, [response, options]);
11863 Roo.callback(options.callback, options.scope, [options, true, response]);
11867 handleFailure : function(response, e){
11868 this.transId = false;
11869 var options = response.argument.options;
11870 response.argument = options ? options.argument : null;
11871 this.fireEvent("requestexception", this, response, options, e);
11872 Roo.callback(options.failure, options.scope, [response, options]);
11873 Roo.callback(options.callback, options.scope, [options, false, response]);
11877 doFormUpload : function(o, ps, url){
11879 var frame = document.createElement('iframe');
11882 frame.className = 'x-hidden';
11884 frame.src = Roo.SSL_SECURE_URL;
11886 document.body.appendChild(frame);
11889 document.frames[id].name = id;
11892 var form = Roo.getDom(o.form);
11894 form.method = 'POST';
11895 form.enctype = form.encoding = 'multipart/form-data';
11901 if(ps){ // add dynamic params
11903 ps = Roo.urlDecode(ps, false);
11905 if(ps.hasOwnProperty(k)){
11906 hd = document.createElement('input');
11907 hd.type = 'hidden';
11910 form.appendChild(hd);
11917 var r = { // bogus response object
11922 r.argument = o ? o.argument : null;
11927 doc = frame.contentWindow.document;
11929 doc = (frame.contentDocument || window.frames[id].document);
11931 if(doc && doc.body){
11932 r.responseText = doc.body.innerHTML;
11934 if(doc && doc.XMLDocument){
11935 r.responseXML = doc.XMLDocument;
11937 r.responseXML = doc;
11944 Roo.EventManager.removeListener(frame, 'load', cb, this);
11946 this.fireEvent("requestcomplete", this, r, o);
11947 Roo.callback(o.success, o.scope, [r, o]);
11948 Roo.callback(o.callback, o.scope, [o, true, r]);
11950 setTimeout(function(){document.body.removeChild(frame);}, 100);
11953 Roo.EventManager.on(frame, 'load', cb, this);
11956 if(hiddens){ // remove dynamic params
11957 for(var i = 0, len = hiddens.length; i < len; i++){
11958 form.removeChild(hiddens[i]);
11962 // this is a 'formdata version???'
11965 doFormDataUpload : function(o, url)
11969 var form = Roo.getDom(o.form);
11970 form.enctype = form.encoding = 'multipart/form-data';
11971 formData = o.formData === true ? new FormData(form) : o.formData;
11973 formData = o.formData === true ? new FormData() : o.formData;
11978 success: this.handleResponse,
11979 failure: this.handleFailure,
11981 argument: {options: o},
11982 timeout : o.timeout || this.timeout
11985 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11989 }else if(this.autoAbort !== false){
11993 //Roo.lib.Ajax.defaultPostHeader = null;
11994 Roo.lib.Ajax.useDefaultHeader = false;
11995 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11996 Roo.lib.Ajax.useDefaultHeader = true;
12004 * Ext JS Library 1.1.1
12005 * Copyright(c) 2006-2007, Ext JS, LLC.
12007 * Originally Released Under LGPL - original licence link has changed is not relivant.
12010 * <script type="text/javascript">
12014 * Global Ajax request class.
12017 * @extends Roo.data.Connection
12020 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
12021 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12022 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
12023 * @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)
12024 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12025 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12026 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12028 Roo.Ajax = new Roo.data.Connection({
12037 * Serialize the passed form into a url encoded string
12039 * @param {String/HTMLElement} form
12042 serializeForm : function(form){
12043 return Roo.lib.Ajax.serializeForm(form);
12047 * Ext JS Library 1.1.1
12048 * Copyright(c) 2006-2007, Ext JS, LLC.
12050 * Originally Released Under LGPL - original licence link has changed is not relivant.
12053 * <script type="text/javascript">
12058 * @class Roo.UpdateManager
12059 * @extends Roo.util.Observable
12060 * Provides AJAX-style update for Element object.<br><br>
12063 * // Get it from a Roo.Element object
12064 * var el = Roo.get("foo");
12065 * var mgr = el.getUpdateManager();
12066 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
12068 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12070 * // or directly (returns the same UpdateManager instance)
12071 * var mgr = new Roo.UpdateManager("myElementId");
12072 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12073 * mgr.on("update", myFcnNeedsToKnow);
12075 // short handed call directly from the element object
12076 Roo.get("foo").load({
12080 text: "Loading Foo..."
12084 * Create new UpdateManager directly.
12085 * @param {String/HTMLElement/Roo.Element} el The element to update
12086 * @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).
12088 Roo.UpdateManager = function(el, forceNew){
12090 if(!forceNew && el.updateManager){
12091 return el.updateManager;
12094 * The Element object
12095 * @type Roo.Element
12099 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12102 this.defaultUrl = null;
12106 * @event beforeupdate
12107 * Fired before an update is made, return false from your handler and the update is cancelled.
12108 * @param {Roo.Element} el
12109 * @param {String/Object/Function} url
12110 * @param {String/Object} params
12112 "beforeupdate": true,
12115 * Fired after successful update is made.
12116 * @param {Roo.Element} el
12117 * @param {Object} oResponseObject The response Object
12122 * Fired on update failure.
12123 * @param {Roo.Element} el
12124 * @param {Object} oResponseObject The response Object
12128 var d = Roo.UpdateManager.defaults;
12130 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12133 this.sslBlankUrl = d.sslBlankUrl;
12135 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12138 this.disableCaching = d.disableCaching;
12140 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12143 this.indicatorText = d.indicatorText;
12145 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12148 this.showLoadIndicator = d.showLoadIndicator;
12150 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12153 this.timeout = d.timeout;
12156 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12159 this.loadScripts = d.loadScripts;
12162 * Transaction object of current executing transaction
12164 this.transaction = null;
12169 this.autoRefreshProcId = null;
12171 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12174 this.refreshDelegate = this.refresh.createDelegate(this);
12176 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12179 this.updateDelegate = this.update.createDelegate(this);
12181 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12184 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12188 this.successDelegate = this.processSuccess.createDelegate(this);
12192 this.failureDelegate = this.processFailure.createDelegate(this);
12194 if(!this.renderer){
12196 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12198 this.renderer = new Roo.UpdateManager.BasicRenderer();
12201 Roo.UpdateManager.superclass.constructor.call(this);
12204 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12206 * Get the Element this UpdateManager is bound to
12207 * @return {Roo.Element} The element
12209 getEl : function(){
12213 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12214 * @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:
12217 url: "your-url.php",<br/>
12218 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12219 callback: yourFunction,<br/>
12220 scope: yourObject, //(optional scope) <br/>
12221 discardUrl: false, <br/>
12222 nocache: false,<br/>
12223 text: "Loading...",<br/>
12225 scripts: false<br/>
12228 * The only required property is url. The optional properties nocache, text and scripts
12229 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12230 * @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}
12231 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12232 * @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.
12234 update : function(url, params, callback, discardUrl){
12235 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12236 var method = this.method,
12238 if(typeof url == "object"){ // must be config object
12241 params = params || cfg.params;
12242 callback = callback || cfg.callback;
12243 discardUrl = discardUrl || cfg.discardUrl;
12244 if(callback && cfg.scope){
12245 callback = callback.createDelegate(cfg.scope);
12247 if(typeof cfg.method != "undefined"){method = cfg.method;};
12248 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12249 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12250 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12251 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12253 this.showLoading();
12255 this.defaultUrl = url;
12257 if(typeof url == "function"){
12258 url = url.call(this);
12261 method = method || (params ? "POST" : "GET");
12262 if(method == "GET"){
12263 url = this.prepareUrl(url);
12266 var o = Roo.apply(cfg ||{}, {
12269 success: this.successDelegate,
12270 failure: this.failureDelegate,
12271 callback: undefined,
12272 timeout: (this.timeout*1000),
12273 argument: {"url": url, "form": null, "callback": callback, "params": params}
12275 Roo.log("updated manager called with timeout of " + o.timeout);
12276 this.transaction = Roo.Ajax.request(o);
12281 * 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.
12282 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12283 * @param {String/HTMLElement} form The form Id or form element
12284 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12285 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12286 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12288 formUpdate : function(form, url, reset, callback){
12289 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12290 if(typeof url == "function"){
12291 url = url.call(this);
12293 form = Roo.getDom(form);
12294 this.transaction = Roo.Ajax.request({
12297 success: this.successDelegate,
12298 failure: this.failureDelegate,
12299 timeout: (this.timeout*1000),
12300 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12302 this.showLoading.defer(1, this);
12307 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12308 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12310 refresh : function(callback){
12311 if(this.defaultUrl == null){
12314 this.update(this.defaultUrl, null, callback, true);
12318 * Set this element to auto refresh.
12319 * @param {Number} interval How often to update (in seconds).
12320 * @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)
12321 * @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}
12322 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12323 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12325 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12327 this.update(url || this.defaultUrl, params, callback, true);
12329 if(this.autoRefreshProcId){
12330 clearInterval(this.autoRefreshProcId);
12332 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12336 * Stop auto refresh on this element.
12338 stopAutoRefresh : function(){
12339 if(this.autoRefreshProcId){
12340 clearInterval(this.autoRefreshProcId);
12341 delete this.autoRefreshProcId;
12345 isAutoRefreshing : function(){
12346 return this.autoRefreshProcId ? true : false;
12349 * Called to update the element to "Loading" state. Override to perform custom action.
12351 showLoading : function(){
12352 if(this.showLoadIndicator){
12353 this.el.update(this.indicatorText);
12358 * Adds unique parameter to query string if disableCaching = true
12361 prepareUrl : function(url){
12362 if(this.disableCaching){
12363 var append = "_dc=" + (new Date().getTime());
12364 if(url.indexOf("?") !== -1){
12365 url += "&" + append;
12367 url += "?" + append;
12376 processSuccess : function(response){
12377 this.transaction = null;
12378 if(response.argument.form && response.argument.reset){
12379 try{ // put in try/catch since some older FF releases had problems with this
12380 response.argument.form.reset();
12383 if(this.loadScripts){
12384 this.renderer.render(this.el, response, this,
12385 this.updateComplete.createDelegate(this, [response]));
12387 this.renderer.render(this.el, response, this);
12388 this.updateComplete(response);
12392 updateComplete : function(response){
12393 this.fireEvent("update", this.el, response);
12394 if(typeof response.argument.callback == "function"){
12395 response.argument.callback(this.el, true, response);
12402 processFailure : function(response){
12403 this.transaction = null;
12404 this.fireEvent("failure", this.el, response);
12405 if(typeof response.argument.callback == "function"){
12406 response.argument.callback(this.el, false, response);
12411 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12412 * @param {Object} renderer The object implementing the render() method
12414 setRenderer : function(renderer){
12415 this.renderer = renderer;
12418 getRenderer : function(){
12419 return this.renderer;
12423 * Set the defaultUrl used for updates
12424 * @param {String/Function} defaultUrl The url or a function to call to get the url
12426 setDefaultUrl : function(defaultUrl){
12427 this.defaultUrl = defaultUrl;
12431 * Aborts the executing transaction
12433 abort : function(){
12434 if(this.transaction){
12435 Roo.Ajax.abort(this.transaction);
12440 * Returns true if an update is in progress
12441 * @return {Boolean}
12443 isUpdating : function(){
12444 if(this.transaction){
12445 return Roo.Ajax.isLoading(this.transaction);
12452 * @class Roo.UpdateManager.defaults
12453 * @static (not really - but it helps the doc tool)
12454 * The defaults collection enables customizing the default properties of UpdateManager
12456 Roo.UpdateManager.defaults = {
12458 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12464 * True to process scripts by default (Defaults to false).
12467 loadScripts : false,
12470 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12473 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12475 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12478 disableCaching : false,
12480 * Whether to show indicatorText when loading (Defaults to true).
12483 showLoadIndicator : true,
12485 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12488 indicatorText : '<div class="loading-indicator">Loading...</div>'
12492 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12494 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12495 * @param {String/HTMLElement/Roo.Element} el The element to update
12496 * @param {String} url The url
12497 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12498 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12501 * @member Roo.UpdateManager
12503 Roo.UpdateManager.updateElement = function(el, url, params, options){
12504 var um = Roo.get(el, true).getUpdateManager();
12505 Roo.apply(um, options);
12506 um.update(url, params, options ? options.callback : null);
12508 // alias for backwards compat
12509 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12511 * @class Roo.UpdateManager.BasicRenderer
12512 * Default Content renderer. Updates the elements innerHTML with the responseText.
12514 Roo.UpdateManager.BasicRenderer = function(){};
12516 Roo.UpdateManager.BasicRenderer.prototype = {
12518 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12519 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12520 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12521 * @param {Roo.Element} el The element being rendered
12522 * @param {Object} response The YUI Connect response object
12523 * @param {UpdateManager} updateManager The calling update manager
12524 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12526 render : function(el, response, updateManager, callback){
12527 el.update(response.responseText, updateManager.loadScripts, callback);
12533 * (c)) Alan Knowles
12539 * @class Roo.DomTemplate
12540 * @extends Roo.Template
12541 * An effort at a dom based template engine..
12543 * Similar to XTemplate, except it uses dom parsing to create the template..
12545 * Supported features:
12550 {a_variable} - output encoded.
12551 {a_variable.format:("Y-m-d")} - call a method on the variable
12552 {a_variable:raw} - unencoded output
12553 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12554 {a_variable:this.method_on_template(...)} - call a method on the template object.
12559 <div roo-for="a_variable or condition.."></div>
12560 <div roo-if="a_variable or condition"></div>
12561 <div roo-exec="some javascript"></div>
12562 <div roo-name="named_template"></div>
12567 Roo.DomTemplate = function()
12569 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12576 Roo.extend(Roo.DomTemplate, Roo.Template, {
12578 * id counter for sub templates.
12582 * flag to indicate if dom parser is inside a pre,
12583 * it will strip whitespace if not.
12588 * The various sub templates
12596 * basic tag replacing syntax
12599 * // you can fake an object call by doing this
12603 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12604 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12606 iterChild : function (node, method) {
12608 var oldPre = this.inPre;
12609 if (node.tagName == 'PRE') {
12612 for( var i = 0; i < node.childNodes.length; i++) {
12613 method.call(this, node.childNodes[i]);
12615 this.inPre = oldPre;
12621 * compile the template
12623 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12626 compile: function()
12630 // covert the html into DOM...
12634 doc = document.implementation.createHTMLDocument("");
12635 doc.documentElement.innerHTML = this.html ;
12636 div = doc.documentElement;
12638 // old IE... - nasty -- it causes all sorts of issues.. with
12639 // images getting pulled from server..
12640 div = document.createElement('div');
12641 div.innerHTML = this.html;
12643 //doc.documentElement.innerHTML = htmlBody
12649 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12651 var tpls = this.tpls;
12653 // create a top level template from the snippet..
12655 //Roo.log(div.innerHTML);
12662 body : div.innerHTML,
12675 Roo.each(tpls, function(tp){
12676 this.compileTpl(tp);
12677 this.tpls[tp.id] = tp;
12680 this.master = tpls[0];
12686 compileNode : function(node, istop) {
12691 // skip anything not a tag..
12692 if (node.nodeType != 1) {
12693 if (node.nodeType == 3 && !this.inPre) {
12694 // reduce white space..
12695 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12718 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12719 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12720 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12721 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12727 // just itterate children..
12728 this.iterChild(node,this.compileNode);
12731 tpl.uid = this.id++;
12732 tpl.value = node.getAttribute('roo-' + tpl.attr);
12733 node.removeAttribute('roo-'+ tpl.attr);
12734 if (tpl.attr != 'name') {
12735 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12736 node.parentNode.replaceChild(placeholder, node);
12739 var placeholder = document.createElement('span');
12740 placeholder.className = 'roo-tpl-' + tpl.value;
12741 node.parentNode.replaceChild(placeholder, node);
12744 // parent now sees '{domtplXXXX}
12745 this.iterChild(node,this.compileNode);
12747 // we should now have node body...
12748 var div = document.createElement('div');
12749 div.appendChild(node);
12751 // this has the unfortunate side effect of converting tagged attributes
12752 // eg. href="{...}" into %7C...%7D
12753 // this has been fixed by searching for those combo's although it's a bit hacky..
12756 tpl.body = div.innerHTML;
12763 switch (tpl.value) {
12764 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12765 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12766 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12771 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12775 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12779 tpl.id = tpl.value; // replace non characters???
12785 this.tpls.push(tpl);
12795 * Compile a segment of the template into a 'sub-template'
12801 compileTpl : function(tpl)
12803 var fm = Roo.util.Format;
12804 var useF = this.disableFormats !== true;
12806 var sep = Roo.isGecko ? "+\n" : ",\n";
12808 var undef = function(str) {
12809 Roo.debug && Roo.log("Property not found :" + str);
12813 //Roo.log(tpl.body);
12817 var fn = function(m, lbrace, name, format, args)
12820 //Roo.log(arguments);
12821 args = args ? args.replace(/\\'/g,"'") : args;
12822 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12823 if (typeof(format) == 'undefined') {
12824 format = 'htmlEncode';
12826 if (format == 'raw' ) {
12830 if(name.substr(0, 6) == 'domtpl'){
12831 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12834 // build an array of options to determine if value is undefined..
12836 // basically get 'xxxx.yyyy' then do
12837 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12838 // (function () { Roo.log("Property not found"); return ''; })() :
12843 Roo.each(name.split('.'), function(st) {
12844 lookfor += (lookfor.length ? '.': '') + st;
12845 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12848 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12851 if(format && useF){
12853 args = args ? ',' + args : "";
12855 if(format.substr(0, 5) != "this."){
12856 format = "fm." + format + '(';
12858 format = 'this.call("'+ format.substr(5) + '", ';
12862 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12865 if (args && args.length) {
12866 // called with xxyx.yuu:(test,test)
12868 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12870 // raw.. - :raw modifier..
12871 return "'"+ sep + udef_st + name + ")"+sep+"'";
12875 // branched to use + in gecko and [].join() in others
12877 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12878 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12881 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12882 body.push(tpl.body.replace(/(\r\n|\n)/g,
12883 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12884 body.push("'].join('');};};");
12885 body = body.join('');
12888 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12890 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12897 * same as applyTemplate, except it's done to one of the subTemplates
12898 * when using named templates, you can do:
12900 * var str = pl.applySubTemplate('your-name', values);
12903 * @param {Number} id of the template
12904 * @param {Object} values to apply to template
12905 * @param {Object} parent (normaly the instance of this object)
12907 applySubTemplate : function(id, values, parent)
12911 var t = this.tpls[id];
12915 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12916 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12920 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12927 if(t.execCall && t.execCall.call(this, values, parent)){
12931 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12937 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12938 parent = t.target ? values : parent;
12939 if(t.forCall && vs instanceof Array){
12941 for(var i = 0, len = vs.length; i < len; i++){
12943 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12945 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12947 //Roo.log(t.compiled);
12951 return buf.join('');
12954 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12959 return t.compiled.call(this, vs, parent);
12961 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12963 //Roo.log(t.compiled);
12971 applyTemplate : function(values){
12972 return this.master.compiled.call(this, values, {});
12973 //var s = this.subs;
12976 apply : function(){
12977 return this.applyTemplate.apply(this, arguments);
12982 Roo.DomTemplate.from = function(el){
12983 el = Roo.getDom(el);
12984 return new Roo.Domtemplate(el.value || el.innerHTML);
12987 * Ext JS Library 1.1.1
12988 * Copyright(c) 2006-2007, Ext JS, LLC.
12990 * Originally Released Under LGPL - original licence link has changed is not relivant.
12993 * <script type="text/javascript">
12997 * @class Roo.util.DelayedTask
12998 * Provides a convenient method of performing setTimeout where a new
12999 * timeout cancels the old timeout. An example would be performing validation on a keypress.
13000 * You can use this class to buffer
13001 * the keypress events for a certain number of milliseconds, and perform only if they stop
13002 * for that amount of time.
13003 * @constructor The parameters to this constructor serve as defaults and are not required.
13004 * @param {Function} fn (optional) The default function to timeout
13005 * @param {Object} scope (optional) The default scope of that timeout
13006 * @param {Array} args (optional) The default Array of arguments
13008 Roo.util.DelayedTask = function(fn, scope, args){
13009 var id = null, d, t;
13011 var call = function(){
13012 var now = new Date().getTime();
13016 fn.apply(scope, args || []);
13020 * Cancels any pending timeout and queues a new one
13021 * @param {Number} delay The milliseconds to delay
13022 * @param {Function} newFn (optional) Overrides function passed to constructor
13023 * @param {Object} newScope (optional) Overrides scope passed to constructor
13024 * @param {Array} newArgs (optional) Overrides args passed to constructor
13026 this.delay = function(delay, newFn, newScope, newArgs){
13027 if(id && delay != d){
13031 t = new Date().getTime();
13033 scope = newScope || scope;
13034 args = newArgs || args;
13036 id = setInterval(call, d);
13041 * Cancel the last queued timeout
13043 this.cancel = function(){
13051 * Ext JS Library 1.1.1
13052 * Copyright(c) 2006-2007, Ext JS, LLC.
13054 * Originally Released Under LGPL - original licence link has changed is not relivant.
13057 * <script type="text/javascript">
13061 Roo.util.TaskRunner = function(interval){
13062 interval = interval || 10;
13063 var tasks = [], removeQueue = [];
13065 var running = false;
13067 var stopThread = function(){
13073 var startThread = function(){
13076 id = setInterval(runTasks, interval);
13080 var removeTask = function(task){
13081 removeQueue.push(task);
13087 var runTasks = function(){
13088 if(removeQueue.length > 0){
13089 for(var i = 0, len = removeQueue.length; i < len; i++){
13090 tasks.remove(removeQueue[i]);
13093 if(tasks.length < 1){
13098 var now = new Date().getTime();
13099 for(var i = 0, len = tasks.length; i < len; ++i){
13101 var itime = now - t.taskRunTime;
13102 if(t.interval <= itime){
13103 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13104 t.taskRunTime = now;
13105 if(rt === false || t.taskRunCount === t.repeat){
13110 if(t.duration && t.duration <= (now - t.taskStartTime)){
13117 * Queues a new task.
13118 * @param {Object} task
13120 this.start = function(task){
13122 task.taskStartTime = new Date().getTime();
13123 task.taskRunTime = 0;
13124 task.taskRunCount = 0;
13129 this.stop = function(task){
13134 this.stopAll = function(){
13136 for(var i = 0, len = tasks.length; i < len; i++){
13137 if(tasks[i].onStop){
13146 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13148 * Ext JS Library 1.1.1
13149 * Copyright(c) 2006-2007, Ext JS, LLC.
13151 * Originally Released Under LGPL - original licence link has changed is not relivant.
13154 * <script type="text/javascript">
13159 * @class Roo.util.MixedCollection
13160 * @extends Roo.util.Observable
13161 * A Collection class that maintains both numeric indexes and keys and exposes events.
13163 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13164 * collection (defaults to false)
13165 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13166 * and return the key value for that item. This is used when available to look up the key on items that
13167 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13168 * equivalent to providing an implementation for the {@link #getKey} method.
13170 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13178 * Fires when the collection is cleared.
13183 * Fires when an item is added to the collection.
13184 * @param {Number} index The index at which the item was added.
13185 * @param {Object} o The item added.
13186 * @param {String} key The key associated with the added item.
13191 * Fires when an item is replaced in the collection.
13192 * @param {String} key he key associated with the new added.
13193 * @param {Object} old The item being replaced.
13194 * @param {Object} new The new item.
13199 * Fires when an item is removed from the collection.
13200 * @param {Object} o The item being removed.
13201 * @param {String} key (optional) The key associated with the removed item.
13206 this.allowFunctions = allowFunctions === true;
13208 this.getKey = keyFn;
13210 Roo.util.MixedCollection.superclass.constructor.call(this);
13213 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13214 allowFunctions : false,
13217 * Adds an item to the collection.
13218 * @param {String} key The key to associate with the item
13219 * @param {Object} o The item to add.
13220 * @return {Object} The item added.
13222 add : function(key, o){
13223 if(arguments.length == 1){
13225 key = this.getKey(o);
13227 if(typeof key == "undefined" || key === null){
13229 this.items.push(o);
13230 this.keys.push(null);
13232 var old = this.map[key];
13234 return this.replace(key, o);
13237 this.items.push(o);
13239 this.keys.push(key);
13241 this.fireEvent("add", this.length-1, o, key);
13246 * MixedCollection has a generic way to fetch keys if you implement getKey.
13249 var mc = new Roo.util.MixedCollection();
13250 mc.add(someEl.dom.id, someEl);
13251 mc.add(otherEl.dom.id, otherEl);
13255 var mc = new Roo.util.MixedCollection();
13256 mc.getKey = function(el){
13262 // or via the constructor
13263 var mc = new Roo.util.MixedCollection(false, function(el){
13269 * @param o {Object} The item for which to find the key.
13270 * @return {Object} The key for the passed item.
13272 getKey : function(o){
13277 * Replaces an item in the collection.
13278 * @param {String} key The key associated with the item to replace, or the item to replace.
13279 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13280 * @return {Object} The new item.
13282 replace : function(key, o){
13283 if(arguments.length == 1){
13285 key = this.getKey(o);
13287 var old = this.item(key);
13288 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13289 return this.add(key, o);
13291 var index = this.indexOfKey(key);
13292 this.items[index] = o;
13294 this.fireEvent("replace", key, old, o);
13299 * Adds all elements of an Array or an Object to the collection.
13300 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13301 * an Array of values, each of which are added to the collection.
13303 addAll : function(objs){
13304 if(arguments.length > 1 || objs instanceof Array){
13305 var args = arguments.length > 1 ? arguments : objs;
13306 for(var i = 0, len = args.length; i < len; i++){
13310 for(var key in objs){
13311 if(this.allowFunctions || typeof objs[key] != "function"){
13312 this.add(key, objs[key]);
13319 * Executes the specified function once for every item in the collection, passing each
13320 * item as the first and only parameter. returning false from the function will stop the iteration.
13321 * @param {Function} fn The function to execute for each item.
13322 * @param {Object} scope (optional) The scope in which to execute the function.
13324 each : function(fn, scope){
13325 var items = [].concat(this.items); // each safe for removal
13326 for(var i = 0, len = items.length; i < len; i++){
13327 if(fn.call(scope || items[i], items[i], i, len) === false){
13334 * Executes the specified function once for every key in the collection, passing each
13335 * key, and its associated item as the first two parameters.
13336 * @param {Function} fn The function to execute for each item.
13337 * @param {Object} scope (optional) The scope in which to execute the function.
13339 eachKey : function(fn, scope){
13340 for(var i = 0, len = this.keys.length; i < len; i++){
13341 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13346 * Returns the first item in the collection which elicits a true return value from the
13347 * passed selection function.
13348 * @param {Function} fn The selection function to execute for each item.
13349 * @param {Object} scope (optional) The scope in which to execute the function.
13350 * @return {Object} The first item in the collection which returned true from the selection function.
13352 find : function(fn, scope){
13353 for(var i = 0, len = this.items.length; i < len; i++){
13354 if(fn.call(scope || window, this.items[i], this.keys[i])){
13355 return this.items[i];
13362 * Inserts an item at the specified index in the collection.
13363 * @param {Number} index The index to insert the item at.
13364 * @param {String} key The key to associate with the new item, or the item itself.
13365 * @param {Object} o (optional) If the second parameter was a key, the new item.
13366 * @return {Object} The item inserted.
13368 insert : function(index, key, o){
13369 if(arguments.length == 2){
13371 key = this.getKey(o);
13373 if(index >= this.length){
13374 return this.add(key, o);
13377 this.items.splice(index, 0, o);
13378 if(typeof key != "undefined" && key != null){
13381 this.keys.splice(index, 0, key);
13382 this.fireEvent("add", index, o, key);
13387 * Removed an item from the collection.
13388 * @param {Object} o The item to remove.
13389 * @return {Object} The item removed.
13391 remove : function(o){
13392 return this.removeAt(this.indexOf(o));
13396 * Remove an item from a specified index in the collection.
13397 * @param {Number} index The index within the collection of the item to remove.
13399 removeAt : function(index){
13400 if(index < this.length && index >= 0){
13402 var o = this.items[index];
13403 this.items.splice(index, 1);
13404 var key = this.keys[index];
13405 if(typeof key != "undefined"){
13406 delete this.map[key];
13408 this.keys.splice(index, 1);
13409 this.fireEvent("remove", o, key);
13414 * Removed an item associated with the passed key fom the collection.
13415 * @param {String} key The key of the item to remove.
13417 removeKey : function(key){
13418 return this.removeAt(this.indexOfKey(key));
13422 * Returns the number of items in the collection.
13423 * @return {Number} the number of items in the collection.
13425 getCount : function(){
13426 return this.length;
13430 * Returns index within the collection of the passed Object.
13431 * @param {Object} o The item to find the index of.
13432 * @return {Number} index of the item.
13434 indexOf : function(o){
13435 if(!this.items.indexOf){
13436 for(var i = 0, len = this.items.length; i < len; i++){
13437 if(this.items[i] == o) {
13443 return this.items.indexOf(o);
13448 * Returns index within the collection of the passed key.
13449 * @param {String} key The key to find the index of.
13450 * @return {Number} index of the key.
13452 indexOfKey : function(key){
13453 if(!this.keys.indexOf){
13454 for(var i = 0, len = this.keys.length; i < len; i++){
13455 if(this.keys[i] == key) {
13461 return this.keys.indexOf(key);
13466 * Returns the item associated with the passed key OR index. Key has priority over index.
13467 * @param {String/Number} key The key or index of the item.
13468 * @return {Object} The item associated with the passed key.
13470 item : function(key){
13471 if (key === 'length') {
13474 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13475 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13479 * Returns the item at the specified index.
13480 * @param {Number} index The index of the item.
13483 itemAt : function(index){
13484 return this.items[index];
13488 * Returns the item associated with the passed key.
13489 * @param {String/Number} key The key of the item.
13490 * @return {Object} The item associated with the passed key.
13492 key : function(key){
13493 return this.map[key];
13497 * Returns true if the collection contains the passed Object as an item.
13498 * @param {Object} o The Object to look for in the collection.
13499 * @return {Boolean} True if the collection contains the Object as an item.
13501 contains : function(o){
13502 return this.indexOf(o) != -1;
13506 * Returns true if the collection contains the passed Object as a key.
13507 * @param {String} key The key to look for in the collection.
13508 * @return {Boolean} True if the collection contains the Object as a key.
13510 containsKey : function(key){
13511 return typeof this.map[key] != "undefined";
13515 * Removes all items from the collection.
13517 clear : function(){
13522 this.fireEvent("clear");
13526 * Returns the first item in the collection.
13527 * @return {Object} the first item in the collection..
13529 first : function(){
13530 return this.items[0];
13534 * Returns the last item in the collection.
13535 * @return {Object} the last item in the collection..
13538 return this.items[this.length-1];
13541 _sort : function(property, dir, fn){
13542 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13543 fn = fn || function(a, b){
13546 var c = [], k = this.keys, items = this.items;
13547 for(var i = 0, len = items.length; i < len; i++){
13548 c[c.length] = {key: k[i], value: items[i], index: i};
13550 c.sort(function(a, b){
13551 var v = fn(a[property], b[property]) * dsc;
13553 v = (a.index < b.index ? -1 : 1);
13557 for(var i = 0, len = c.length; i < len; i++){
13558 items[i] = c[i].value;
13561 this.fireEvent("sort", this);
13565 * Sorts this collection with the passed comparison function
13566 * @param {String} direction (optional) "ASC" or "DESC"
13567 * @param {Function} fn (optional) comparison function
13569 sort : function(dir, fn){
13570 this._sort("value", dir, fn);
13574 * Sorts this collection by keys
13575 * @param {String} direction (optional) "ASC" or "DESC"
13576 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13578 keySort : function(dir, fn){
13579 this._sort("key", dir, fn || function(a, b){
13580 return String(a).toUpperCase()-String(b).toUpperCase();
13585 * Returns a range of items in this collection
13586 * @param {Number} startIndex (optional) defaults to 0
13587 * @param {Number} endIndex (optional) default to the last item
13588 * @return {Array} An array of items
13590 getRange : function(start, end){
13591 var items = this.items;
13592 if(items.length < 1){
13595 start = start || 0;
13596 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13599 for(var i = start; i <= end; i++) {
13600 r[r.length] = items[i];
13603 for(var i = start; i >= end; i--) {
13604 r[r.length] = items[i];
13611 * Filter the <i>objects</i> in this collection by a specific property.
13612 * Returns a new collection that has been filtered.
13613 * @param {String} property A property on your objects
13614 * @param {String/RegExp} value Either string that the property values
13615 * should start with or a RegExp to test against the property
13616 * @return {MixedCollection} The new filtered collection
13618 filter : function(property, value){
13619 if(!value.exec){ // not a regex
13620 value = String(value);
13621 if(value.length == 0){
13622 return this.clone();
13624 value = new RegExp("^" + Roo.escapeRe(value), "i");
13626 return this.filterBy(function(o){
13627 return o && value.test(o[property]);
13632 * Filter by a function. * Returns a new collection that has been filtered.
13633 * The passed function will be called with each
13634 * object in the collection. If the function returns true, the value is included
13635 * otherwise it is filtered.
13636 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13637 * @param {Object} scope (optional) The scope of the function (defaults to this)
13638 * @return {MixedCollection} The new filtered collection
13640 filterBy : function(fn, scope){
13641 var r = new Roo.util.MixedCollection();
13642 r.getKey = this.getKey;
13643 var k = this.keys, it = this.items;
13644 for(var i = 0, len = it.length; i < len; i++){
13645 if(fn.call(scope||this, it[i], k[i])){
13646 r.add(k[i], it[i]);
13653 * Creates a duplicate of this collection
13654 * @return {MixedCollection}
13656 clone : function(){
13657 var r = new Roo.util.MixedCollection();
13658 var k = this.keys, it = this.items;
13659 for(var i = 0, len = it.length; i < len; i++){
13660 r.add(k[i], it[i]);
13662 r.getKey = this.getKey;
13667 * Returns the item associated with the passed key or index.
13669 * @param {String/Number} key The key or index of the item.
13670 * @return {Object} The item associated with the passed key.
13672 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13674 * Ext JS Library 1.1.1
13675 * Copyright(c) 2006-2007, Ext JS, LLC.
13677 * Originally Released Under LGPL - original licence link has changed is not relivant.
13680 * <script type="text/javascript">
13683 * @class Roo.util.JSON
13684 * Modified version of Douglas Crockford"s json.js that doesn"t
13685 * mess with the Object prototype
13686 * http://www.json.org/js.html
13689 Roo.util.JSON = new (function(){
13690 var useHasOwn = {}.hasOwnProperty ? true : false;
13692 // crashes Safari in some instances
13693 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13695 var pad = function(n) {
13696 return n < 10 ? "0" + n : n;
13709 var encodeString = function(s){
13710 if (/["\\\x00-\x1f]/.test(s)) {
13711 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13716 c = b.charCodeAt();
13718 Math.floor(c / 16).toString(16) +
13719 (c % 16).toString(16);
13722 return '"' + s + '"';
13725 var encodeArray = function(o){
13726 var a = ["["], b, i, l = o.length, v;
13727 for (i = 0; i < l; i += 1) {
13729 switch (typeof v) {
13738 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13746 var encodeDate = function(o){
13747 return '"' + o.getFullYear() + "-" +
13748 pad(o.getMonth() + 1) + "-" +
13749 pad(o.getDate()) + "T" +
13750 pad(o.getHours()) + ":" +
13751 pad(o.getMinutes()) + ":" +
13752 pad(o.getSeconds()) + '"';
13756 * Encodes an Object, Array or other value
13757 * @param {Mixed} o The variable to encode
13758 * @return {String} The JSON string
13760 this.encode = function(o)
13762 // should this be extended to fully wrap stringify..
13764 if(typeof o == "undefined" || o === null){
13766 }else if(o instanceof Array){
13767 return encodeArray(o);
13768 }else if(o instanceof Date){
13769 return encodeDate(o);
13770 }else if(typeof o == "string"){
13771 return encodeString(o);
13772 }else if(typeof o == "number"){
13773 return isFinite(o) ? String(o) : "null";
13774 }else if(typeof o == "boolean"){
13777 var a = ["{"], b, i, v;
13779 if(!useHasOwn || o.hasOwnProperty(i)) {
13781 switch (typeof v) {
13790 a.push(this.encode(i), ":",
13791 v === null ? "null" : this.encode(v));
13802 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13803 * @param {String} json The JSON string
13804 * @return {Object} The resulting object
13806 this.decode = function(json){
13808 return /** eval:var:json */ eval("(" + json + ')');
13812 * Shorthand for {@link Roo.util.JSON#encode}
13813 * @member Roo encode
13815 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13817 * Shorthand for {@link Roo.util.JSON#decode}
13818 * @member Roo decode
13820 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13823 * Ext JS Library 1.1.1
13824 * Copyright(c) 2006-2007, Ext JS, LLC.
13826 * Originally Released Under LGPL - original licence link has changed is not relivant.
13829 * <script type="text/javascript">
13833 * @class Roo.util.Format
13834 * Reusable data formatting functions
13837 Roo.util.Format = function(){
13838 var trimRe = /^\s+|\s+$/g;
13841 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13842 * @param {String} value The string to truncate
13843 * @param {Number} length The maximum length to allow before truncating
13844 * @return {String} The converted text
13846 ellipsis : function(value, len){
13847 if(value && value.length > len){
13848 return value.substr(0, len-3)+"...";
13854 * Checks a reference and converts it to empty string if it is undefined
13855 * @param {Mixed} value Reference to check
13856 * @return {Mixed} Empty string if converted, otherwise the original value
13858 undef : function(value){
13859 return typeof value != "undefined" ? value : "";
13863 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13864 * @param {String} value The string to encode
13865 * @return {String} The encoded text
13867 htmlEncode : function(value){
13868 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13872 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13873 * @param {String} value The string to decode
13874 * @return {String} The decoded text
13876 htmlDecode : function(value){
13877 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13881 * Trims any whitespace from either side of a string
13882 * @param {String} value The text to trim
13883 * @return {String} The trimmed text
13885 trim : function(value){
13886 return String(value).replace(trimRe, "");
13890 * Returns a substring from within an original string
13891 * @param {String} value The original text
13892 * @param {Number} start The start index of the substring
13893 * @param {Number} length The length of the substring
13894 * @return {String} The substring
13896 substr : function(value, start, length){
13897 return String(value).substr(start, length);
13901 * Converts a string to all lower case letters
13902 * @param {String} value The text to convert
13903 * @return {String} The converted text
13905 lowercase : function(value){
13906 return String(value).toLowerCase();
13910 * Converts a string to all upper case letters
13911 * @param {String} value The text to convert
13912 * @return {String} The converted text
13914 uppercase : function(value){
13915 return String(value).toUpperCase();
13919 * Converts the first character only of a string to upper case
13920 * @param {String} value The text to convert
13921 * @return {String} The converted text
13923 capitalize : function(value){
13924 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13928 call : function(value, fn){
13929 if(arguments.length > 2){
13930 var args = Array.prototype.slice.call(arguments, 2);
13931 args.unshift(value);
13933 return /** eval:var:value */ eval(fn).apply(window, args);
13935 /** eval:var:value */
13936 return /** eval:var:value */ eval(fn).call(window, value);
13942 * safer version of Math.toFixed..??/
13943 * @param {Number/String} value The numeric value to format
13944 * @param {Number/String} value Decimal places
13945 * @return {String} The formatted currency string
13947 toFixed : function(v, n)
13949 // why not use to fixed - precision is buggered???
13951 return Math.round(v-0);
13953 var fact = Math.pow(10,n+1);
13954 v = (Math.round((v-0)*fact))/fact;
13955 var z = (''+fact).substring(2);
13956 if (v == Math.floor(v)) {
13957 return Math.floor(v) + '.' + z;
13960 // now just padd decimals..
13961 var ps = String(v).split('.');
13962 var fd = (ps[1] + z);
13963 var r = fd.substring(0,n);
13964 var rm = fd.substring(n);
13966 return ps[0] + '.' + r;
13968 r*=1; // turn it into a number;
13970 if (String(r).length != n) {
13973 r = String(r).substring(1); // chop the end off.
13976 return ps[0] + '.' + r;
13981 * Format a number as US currency
13982 * @param {Number/String} value The numeric value to format
13983 * @return {String} The formatted currency string
13985 usMoney : function(v){
13986 return '$' + Roo.util.Format.number(v);
13991 * eventually this should probably emulate php's number_format
13992 * @param {Number/String} value The numeric value to format
13993 * @param {Number} decimals number of decimal places
13994 * @param {String} delimiter for thousands (default comma)
13995 * @return {String} The formatted currency string
13997 number : function(v, decimals, thousandsDelimiter)
13999 // multiply and round.
14000 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14001 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14003 var mul = Math.pow(10, decimals);
14004 var zero = String(mul).substring(1);
14005 v = (Math.round((v-0)*mul))/mul;
14007 // if it's '0' number.. then
14009 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14011 var ps = v.split('.');
14014 var r = /(\d+)(\d{3})/;
14017 if(thousandsDelimiter.length != 0) {
14018 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14023 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14024 // does not have decimals
14025 (decimals ? ('.' + zero) : '');
14028 return whole + sub ;
14032 * Parse a value into a formatted date using the specified format pattern.
14033 * @param {Mixed} value The value to format
14034 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14035 * @return {String} The formatted date string
14037 date : function(v, format){
14041 if(!(v instanceof Date)){
14042 v = new Date(Date.parse(v));
14044 return v.dateFormat(format || Roo.util.Format.defaults.date);
14048 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14049 * @param {String} format Any valid date format string
14050 * @return {Function} The date formatting function
14052 dateRenderer : function(format){
14053 return function(v){
14054 return Roo.util.Format.date(v, format);
14059 stripTagsRE : /<\/?[^>]+>/gi,
14062 * Strips all HTML tags
14063 * @param {Mixed} value The text from which to strip tags
14064 * @return {String} The stripped text
14066 stripTags : function(v){
14067 return !v ? v : String(v).replace(this.stripTagsRE, "");
14071 * Size in Mb,Gb etc.
14072 * @param {Number} value The number to be formated
14073 * @param {number} decimals how many decimal places
14074 * @return {String} the formated string
14076 size : function(value, decimals)
14078 var sizes = ['b', 'k', 'M', 'G', 'T'];
14082 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14083 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
14090 Roo.util.Format.defaults = {
14094 * Ext JS Library 1.1.1
14095 * Copyright(c) 2006-2007, Ext JS, LLC.
14097 * Originally Released Under LGPL - original licence link has changed is not relivant.
14100 * <script type="text/javascript">
14107 * @class Roo.MasterTemplate
14108 * @extends Roo.Template
14109 * Provides a template that can have child templates. The syntax is:
14111 var t = new Roo.MasterTemplate(
14112 '<select name="{name}">',
14113 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14116 t.add('options', {value: 'foo', text: 'bar'});
14117 // or you can add multiple child elements in one shot
14118 t.addAll('options', [
14119 {value: 'foo', text: 'bar'},
14120 {value: 'foo2', text: 'bar2'},
14121 {value: 'foo3', text: 'bar3'}
14123 // then append, applying the master template values
14124 t.append('my-form', {name: 'my-select'});
14126 * A name attribute for the child template is not required if you have only one child
14127 * template or you want to refer to them by index.
14129 Roo.MasterTemplate = function(){
14130 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14131 this.originalHtml = this.html;
14133 var m, re = this.subTemplateRe;
14136 while(m = re.exec(this.html)){
14137 var name = m[1], content = m[2];
14142 tpl : new Roo.Template(content)
14145 st[name] = st[subIndex];
14147 st[subIndex].tpl.compile();
14148 st[subIndex].tpl.call = this.call.createDelegate(this);
14151 this.subCount = subIndex;
14154 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14156 * The regular expression used to match sub templates
14160 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14163 * Applies the passed values to a child template.
14164 * @param {String/Number} name (optional) The name or index of the child template
14165 * @param {Array/Object} values The values to be applied to the template
14166 * @return {MasterTemplate} this
14168 add : function(name, values){
14169 if(arguments.length == 1){
14170 values = arguments[0];
14173 var s = this.subs[name];
14174 s.buffer[s.buffer.length] = s.tpl.apply(values);
14179 * Applies all the passed values to a child template.
14180 * @param {String/Number} name (optional) The name or index of the child template
14181 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14182 * @param {Boolean} reset (optional) True to reset the template first
14183 * @return {MasterTemplate} this
14185 fill : function(name, values, reset){
14187 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14195 for(var i = 0, len = values.length; i < len; i++){
14196 this.add(name, values[i]);
14202 * Resets the template for reuse
14203 * @return {MasterTemplate} this
14205 reset : function(){
14207 for(var i = 0; i < this.subCount; i++){
14213 applyTemplate : function(values){
14215 var replaceIndex = -1;
14216 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14217 return s[++replaceIndex].buffer.join("");
14219 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14222 apply : function(){
14223 return this.applyTemplate.apply(this, arguments);
14226 compile : function(){return this;}
14230 * Alias for fill().
14233 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14235 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14236 * var tpl = Roo.MasterTemplate.from('element-id');
14237 * @param {String/HTMLElement} el
14238 * @param {Object} config
14241 Roo.MasterTemplate.from = function(el, config){
14242 el = Roo.getDom(el);
14243 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14246 * Ext JS Library 1.1.1
14247 * Copyright(c) 2006-2007, Ext JS, LLC.
14249 * Originally Released Under LGPL - original licence link has changed is not relivant.
14252 * <script type="text/javascript">
14257 * @class Roo.util.CSS
14258 * Utility class for manipulating CSS rules
14261 Roo.util.CSS = function(){
14263 var doc = document;
14265 var camelRe = /(-[a-z])/gi;
14266 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14270 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14271 * tag and appended to the HEAD of the document.
14272 * @param {String|Object} cssText The text containing the css rules
14273 * @param {String} id An id to add to the stylesheet for later removal
14274 * @return {StyleSheet}
14276 createStyleSheet : function(cssText, id){
14278 var head = doc.getElementsByTagName("head")[0];
14279 var nrules = doc.createElement("style");
14280 nrules.setAttribute("type", "text/css");
14282 nrules.setAttribute("id", id);
14284 if (typeof(cssText) != 'string') {
14285 // support object maps..
14286 // not sure if this a good idea..
14287 // perhaps it should be merged with the general css handling
14288 // and handle js style props.
14289 var cssTextNew = [];
14290 for(var n in cssText) {
14292 for(var k in cssText[n]) {
14293 citems.push( k + ' : ' +cssText[n][k] + ';' );
14295 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14298 cssText = cssTextNew.join("\n");
14304 head.appendChild(nrules);
14305 ss = nrules.styleSheet;
14306 ss.cssText = cssText;
14309 nrules.appendChild(doc.createTextNode(cssText));
14311 nrules.cssText = cssText;
14313 head.appendChild(nrules);
14314 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14316 this.cacheStyleSheet(ss);
14321 * Removes a style or link tag by id
14322 * @param {String} id The id of the tag
14324 removeStyleSheet : function(id){
14325 var existing = doc.getElementById(id);
14327 existing.parentNode.removeChild(existing);
14332 * Dynamically swaps an existing stylesheet reference for a new one
14333 * @param {String} id The id of an existing link tag to remove
14334 * @param {String} url The href of the new stylesheet to include
14336 swapStyleSheet : function(id, url){
14337 this.removeStyleSheet(id);
14338 var ss = doc.createElement("link");
14339 ss.setAttribute("rel", "stylesheet");
14340 ss.setAttribute("type", "text/css");
14341 ss.setAttribute("id", id);
14342 ss.setAttribute("href", url);
14343 doc.getElementsByTagName("head")[0].appendChild(ss);
14347 * Refresh the rule cache if you have dynamically added stylesheets
14348 * @return {Object} An object (hash) of rules indexed by selector
14350 refreshCache : function(){
14351 return this.getRules(true);
14355 cacheStyleSheet : function(stylesheet){
14359 try{// try catch for cross domain access issue
14360 var ssRules = stylesheet.cssRules || stylesheet.rules;
14361 for(var j = ssRules.length-1; j >= 0; --j){
14362 rules[ssRules[j].selectorText] = ssRules[j];
14368 * Gets all css rules for the document
14369 * @param {Boolean} refreshCache true to refresh the internal cache
14370 * @return {Object} An object (hash) of rules indexed by selector
14372 getRules : function(refreshCache){
14373 if(rules == null || refreshCache){
14375 var ds = doc.styleSheets;
14376 for(var i =0, len = ds.length; i < len; i++){
14378 this.cacheStyleSheet(ds[i]);
14386 * Gets an an individual CSS rule by selector(s)
14387 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14388 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14389 * @return {CSSRule} The CSS rule or null if one is not found
14391 getRule : function(selector, refreshCache){
14392 var rs = this.getRules(refreshCache);
14393 if(!(selector instanceof Array)){
14394 return rs[selector];
14396 for(var i = 0; i < selector.length; i++){
14397 if(rs[selector[i]]){
14398 return rs[selector[i]];
14406 * Updates a rule property
14407 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14408 * @param {String} property The css property
14409 * @param {String} value The new value for the property
14410 * @return {Boolean} true If a rule was found and updated
14412 updateRule : function(selector, property, value){
14413 if(!(selector instanceof Array)){
14414 var rule = this.getRule(selector);
14416 rule.style[property.replace(camelRe, camelFn)] = value;
14420 for(var i = 0; i < selector.length; i++){
14421 if(this.updateRule(selector[i], property, value)){
14431 * Ext JS Library 1.1.1
14432 * Copyright(c) 2006-2007, Ext JS, LLC.
14434 * Originally Released Under LGPL - original licence link has changed is not relivant.
14437 * <script type="text/javascript">
14443 * @class Roo.util.ClickRepeater
14444 * @extends Roo.util.Observable
14446 * A wrapper class which can be applied to any element. Fires a "click" event while the
14447 * mouse is pressed. The interval between firings may be specified in the config but
14448 * defaults to 10 milliseconds.
14450 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14452 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14453 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14454 * Similar to an autorepeat key delay.
14455 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14456 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14457 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14458 * "interval" and "delay" are ignored. "immediate" is honored.
14459 * @cfg {Boolean} preventDefault True to prevent the default click event
14460 * @cfg {Boolean} stopDefault True to stop the default click event
14463 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14464 * 2007-02-02 jvs Renamed to ClickRepeater
14465 * 2007-02-03 jvs Modifications for FF Mac and Safari
14468 * @param {String/HTMLElement/Element} el The element to listen on
14469 * @param {Object} config
14471 Roo.util.ClickRepeater = function(el, config)
14473 this.el = Roo.get(el);
14474 this.el.unselectable();
14476 Roo.apply(this, config);
14481 * Fires when the mouse button is depressed.
14482 * @param {Roo.util.ClickRepeater} this
14484 "mousedown" : true,
14487 * Fires on a specified interval during the time the element is pressed.
14488 * @param {Roo.util.ClickRepeater} this
14493 * Fires when the mouse key is released.
14494 * @param {Roo.util.ClickRepeater} this
14499 this.el.on("mousedown", this.handleMouseDown, this);
14500 if(this.preventDefault || this.stopDefault){
14501 this.el.on("click", function(e){
14502 if(this.preventDefault){
14503 e.preventDefault();
14505 if(this.stopDefault){
14511 // allow inline handler
14513 this.on("click", this.handler, this.scope || this);
14516 Roo.util.ClickRepeater.superclass.constructor.call(this);
14519 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14522 preventDefault : true,
14523 stopDefault : false,
14527 handleMouseDown : function(){
14528 clearTimeout(this.timer);
14530 if(this.pressClass){
14531 this.el.addClass(this.pressClass);
14533 this.mousedownTime = new Date();
14535 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14536 this.el.on("mouseout", this.handleMouseOut, this);
14538 this.fireEvent("mousedown", this);
14539 this.fireEvent("click", this);
14541 this.timer = this.click.defer(this.delay || this.interval, this);
14545 click : function(){
14546 this.fireEvent("click", this);
14547 this.timer = this.click.defer(this.getInterval(), this);
14551 getInterval: function(){
14552 if(!this.accelerate){
14553 return this.interval;
14555 var pressTime = this.mousedownTime.getElapsed();
14556 if(pressTime < 500){
14558 }else if(pressTime < 1700){
14560 }else if(pressTime < 2600){
14562 }else if(pressTime < 3500){
14564 }else if(pressTime < 4400){
14566 }else if(pressTime < 5300){
14568 }else if(pressTime < 6200){
14576 handleMouseOut : function(){
14577 clearTimeout(this.timer);
14578 if(this.pressClass){
14579 this.el.removeClass(this.pressClass);
14581 this.el.on("mouseover", this.handleMouseReturn, this);
14585 handleMouseReturn : function(){
14586 this.el.un("mouseover", this.handleMouseReturn);
14587 if(this.pressClass){
14588 this.el.addClass(this.pressClass);
14594 handleMouseUp : function(){
14595 clearTimeout(this.timer);
14596 this.el.un("mouseover", this.handleMouseReturn);
14597 this.el.un("mouseout", this.handleMouseOut);
14598 Roo.get(document).un("mouseup", this.handleMouseUp);
14599 this.el.removeClass(this.pressClass);
14600 this.fireEvent("mouseup", this);
14603 * @class Roo.util.Clipboard
14609 Roo.util.Clipboard = {
14611 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
14612 * @param {String} text to copy to clipboard
14614 write : function(text) {
14615 // navigator clipboard api needs a secure context (https)
14616 if (navigator.clipboard && window.isSecureContext) {
14617 // navigator clipboard api method'
14618 navigator.clipboard.writeText(text);
14621 // text area method
14622 var ta = document.createElement("textarea");
14624 // make the textarea out of viewport
14625 ta.style.position = "fixed";
14626 ta.style.left = "-999999px";
14627 ta.style.top = "-999999px";
14628 document.body.appendChild(ta);
14631 document.execCommand('copy');
14641 * Ext JS Library 1.1.1
14642 * Copyright(c) 2006-2007, Ext JS, LLC.
14644 * Originally Released Under LGPL - original licence link has changed is not relivant.
14647 * <script type="text/javascript">
14652 * @class Roo.KeyNav
14653 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14654 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14655 * way to implement custom navigation schemes for any UI component.</p>
14656 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14657 * pageUp, pageDown, del, home, end. Usage:</p>
14659 var nav = new Roo.KeyNav("my-element", {
14660 "left" : function(e){
14661 this.moveLeft(e.ctrlKey);
14663 "right" : function(e){
14664 this.moveRight(e.ctrlKey);
14666 "enter" : function(e){
14673 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14674 * @param {Object} config The config
14676 Roo.KeyNav = function(el, config){
14677 this.el = Roo.get(el);
14678 Roo.apply(this, config);
14679 if(!this.disabled){
14680 this.disabled = true;
14685 Roo.KeyNav.prototype = {
14687 * @cfg {Boolean} disabled
14688 * True to disable this KeyNav instance (defaults to false)
14692 * @cfg {String} defaultEventAction
14693 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14694 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14695 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14697 defaultEventAction: "stopEvent",
14699 * @cfg {Boolean} forceKeyDown
14700 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14701 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14702 * handle keydown instead of keypress.
14704 forceKeyDown : false,
14707 prepareEvent : function(e){
14708 var k = e.getKey();
14709 var h = this.keyToHandler[k];
14710 //if(h && this[h]){
14711 // e.stopPropagation();
14713 if(Roo.isSafari && h && k >= 37 && k <= 40){
14719 relay : function(e){
14720 var k = e.getKey();
14721 var h = this.keyToHandler[k];
14723 if(this.doRelay(e, this[h], h) !== true){
14724 e[this.defaultEventAction]();
14730 doRelay : function(e, h, hname){
14731 return h.call(this.scope || this, e);
14734 // possible handlers
14748 // quick lookup hash
14765 * Enable this KeyNav
14767 enable: function(){
14769 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14770 // the EventObject will normalize Safari automatically
14771 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14772 this.el.on("keydown", this.relay, this);
14774 this.el.on("keydown", this.prepareEvent, this);
14775 this.el.on("keypress", this.relay, this);
14777 this.disabled = false;
14782 * Disable this KeyNav
14784 disable: function(){
14785 if(!this.disabled){
14786 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14787 this.el.un("keydown", this.relay);
14789 this.el.un("keydown", this.prepareEvent);
14790 this.el.un("keypress", this.relay);
14792 this.disabled = true;
14797 * Ext JS Library 1.1.1
14798 * Copyright(c) 2006-2007, Ext JS, LLC.
14800 * Originally Released Under LGPL - original licence link has changed is not relivant.
14803 * <script type="text/javascript">
14808 * @class Roo.KeyMap
14809 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14810 * The constructor accepts the same config object as defined by {@link #addBinding}.
14811 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14812 * combination it will call the function with this signature (if the match is a multi-key
14813 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14814 * A KeyMap can also handle a string representation of keys.<br />
14817 // map one key by key code
14818 var map = new Roo.KeyMap("my-element", {
14819 key: 13, // or Roo.EventObject.ENTER
14824 // map multiple keys to one action by string
14825 var map = new Roo.KeyMap("my-element", {
14831 // map multiple keys to multiple actions by strings and array of codes
14832 var map = new Roo.KeyMap("my-element", [
14835 fn: function(){ alert("Return was pressed"); }
14838 fn: function(){ alert('a, b or c was pressed'); }
14843 fn: function(){ alert('Control + shift + tab was pressed.'); }
14847 * <b>Note: A KeyMap starts enabled</b>
14849 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14850 * @param {Object} config The config (see {@link #addBinding})
14851 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14853 Roo.KeyMap = function(el, config, eventName){
14854 this.el = Roo.get(el);
14855 this.eventName = eventName || "keydown";
14856 this.bindings = [];
14858 this.addBinding(config);
14863 Roo.KeyMap.prototype = {
14865 * True to stop the event from bubbling and prevent the default browser action if the
14866 * key was handled by the KeyMap (defaults to false)
14872 * Add a new binding to this KeyMap. The following config object properties are supported:
14874 Property Type Description
14875 ---------- --------------- ----------------------------------------------------------------------
14876 key String/Array A single keycode or an array of keycodes to handle
14877 shift Boolean True to handle key only when shift is pressed (defaults to false)
14878 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14879 alt Boolean True to handle key only when alt is pressed (defaults to false)
14880 fn Function The function to call when KeyMap finds the expected key combination
14881 scope Object The scope of the callback function
14887 var map = new Roo.KeyMap(document, {
14888 key: Roo.EventObject.ENTER,
14893 //Add a new binding to the existing KeyMap later
14901 * @param {Object/Array} config A single KeyMap config or an array of configs
14903 addBinding : function(config){
14904 if(config instanceof Array){
14905 for(var i = 0, len = config.length; i < len; i++){
14906 this.addBinding(config[i]);
14910 var keyCode = config.key,
14911 shift = config.shift,
14912 ctrl = config.ctrl,
14915 scope = config.scope;
14916 if(typeof keyCode == "string"){
14918 var keyString = keyCode.toUpperCase();
14919 for(var j = 0, len = keyString.length; j < len; j++){
14920 ks.push(keyString.charCodeAt(j));
14924 var keyArray = keyCode instanceof Array;
14925 var handler = function(e){
14926 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14927 var k = e.getKey();
14929 for(var i = 0, len = keyCode.length; i < len; i++){
14930 if(keyCode[i] == k){
14931 if(this.stopEvent){
14934 fn.call(scope || window, k, e);
14940 if(this.stopEvent){
14943 fn.call(scope || window, k, e);
14948 this.bindings.push(handler);
14952 * Shorthand for adding a single key listener
14953 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14954 * following options:
14955 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14956 * @param {Function} fn The function to call
14957 * @param {Object} scope (optional) The scope of the function
14959 on : function(key, fn, scope){
14960 var keyCode, shift, ctrl, alt;
14961 if(typeof key == "object" && !(key instanceof Array)){
14980 handleKeyDown : function(e){
14981 if(this.enabled){ //just in case
14982 var b = this.bindings;
14983 for(var i = 0, len = b.length; i < len; i++){
14984 b[i].call(this, e);
14990 * Returns true if this KeyMap is enabled
14991 * @return {Boolean}
14993 isEnabled : function(){
14994 return this.enabled;
14998 * Enables this KeyMap
15000 enable: function(){
15002 this.el.on(this.eventName, this.handleKeyDown, this);
15003 this.enabled = true;
15008 * Disable this KeyMap
15010 disable: function(){
15012 this.el.removeListener(this.eventName, this.handleKeyDown, this);
15013 this.enabled = false;
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">
15029 * @class Roo.util.TextMetrics
15030 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15031 * wide, in pixels, a given block of text will be.
15034 Roo.util.TextMetrics = function(){
15038 * Measures the size of the specified text
15039 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15040 * that can affect the size of the rendered text
15041 * @param {String} text The text to measure
15042 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15043 * in order to accurately measure the text height
15044 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15046 measure : function(el, text, fixedWidth){
15048 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15051 shared.setFixedWidth(fixedWidth || 'auto');
15052 return shared.getSize(text);
15056 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
15057 * the overhead of multiple calls to initialize the style properties on each measurement.
15058 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15059 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15060 * in order to accurately measure the text height
15061 * @return {Roo.util.TextMetrics.Instance} instance The new instance
15063 createInstance : function(el, fixedWidth){
15064 return Roo.util.TextMetrics.Instance(el, fixedWidth);
15071 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
15072 var ml = new Roo.Element(document.createElement('div'));
15073 document.body.appendChild(ml.dom);
15074 ml.position('absolute');
15075 ml.setLeftTop(-1000, -1000);
15079 ml.setWidth(fixedWidth);
15084 * Returns the size of the specified text based on the internal element's style and width properties
15085 * @memberOf Roo.util.TextMetrics.Instance#
15086 * @param {String} text The text to measure
15087 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15089 getSize : function(text){
15091 var s = ml.getSize();
15097 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15098 * that can affect the size of the rendered text
15099 * @memberOf Roo.util.TextMetrics.Instance#
15100 * @param {String/HTMLElement} el The element, dom node or id
15102 bind : function(el){
15104 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15109 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15110 * to set a fixed width in order to accurately measure the text height.
15111 * @memberOf Roo.util.TextMetrics.Instance#
15112 * @param {Number} width The width to set on the element
15114 setFixedWidth : function(width){
15115 ml.setWidth(width);
15119 * Returns the measured width of the specified text
15120 * @memberOf Roo.util.TextMetrics.Instance#
15121 * @param {String} text The text to measure
15122 * @return {Number} width The width in pixels
15124 getWidth : function(text){
15125 ml.dom.style.width = 'auto';
15126 return this.getSize(text).width;
15130 * Returns the measured height of the specified text. For multiline text, be sure to call
15131 * {@link #setFixedWidth} if necessary.
15132 * @memberOf Roo.util.TextMetrics.Instance#
15133 * @param {String} text The text to measure
15134 * @return {Number} height The height in pixels
15136 getHeight : function(text){
15137 return this.getSize(text).height;
15141 instance.bind(bindTo);
15146 // backwards compat
15147 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15149 * Ext JS Library 1.1.1
15150 * Copyright(c) 2006-2007, Ext JS, LLC.
15152 * Originally Released Under LGPL - original licence link has changed is not relivant.
15155 * <script type="text/javascript">
15159 * @class Roo.state.Provider
15160 * Abstract base class for state provider implementations. This class provides methods
15161 * for encoding and decoding <b>typed</b> variables including dates and defines the
15162 * Provider interface.
15164 Roo.state.Provider = function(){
15166 * @event statechange
15167 * Fires when a state change occurs.
15168 * @param {Provider} this This state provider
15169 * @param {String} key The state key which was changed
15170 * @param {String} value The encoded value for the state
15173 "statechange": true
15176 Roo.state.Provider.superclass.constructor.call(this);
15178 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15180 * Returns the current value for a key
15181 * @param {String} name The key name
15182 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15183 * @return {Mixed} The state data
15185 get : function(name, defaultValue){
15186 return typeof this.state[name] == "undefined" ?
15187 defaultValue : this.state[name];
15191 * Clears a value from the state
15192 * @param {String} name The key name
15194 clear : function(name){
15195 delete this.state[name];
15196 this.fireEvent("statechange", this, name, null);
15200 * Sets the value for a key
15201 * @param {String} name The key name
15202 * @param {Mixed} value The value to set
15204 set : function(name, value){
15205 this.state[name] = value;
15206 this.fireEvent("statechange", this, name, value);
15210 * Decodes a string previously encoded with {@link #encodeValue}.
15211 * @param {String} value The value to decode
15212 * @return {Mixed} The decoded value
15214 decodeValue : function(cookie){
15215 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15216 var matches = re.exec(unescape(cookie));
15217 if(!matches || !matches[1]) {
15218 return; // non state cookie
15220 var type = matches[1];
15221 var v = matches[2];
15224 return parseFloat(v);
15226 return new Date(Date.parse(v));
15231 var values = v.split("^");
15232 for(var i = 0, len = values.length; i < len; i++){
15233 all.push(this.decodeValue(values[i]));
15238 var values = v.split("^");
15239 for(var i = 0, len = values.length; i < len; i++){
15240 var kv = values[i].split("=");
15241 all[kv[0]] = this.decodeValue(kv[1]);
15250 * Encodes a value including type information. Decode with {@link #decodeValue}.
15251 * @param {Mixed} value The value to encode
15252 * @return {String} The encoded value
15254 encodeValue : function(v){
15256 if(typeof v == "number"){
15258 }else if(typeof v == "boolean"){
15259 enc = "b:" + (v ? "1" : "0");
15260 }else if(v instanceof Date){
15261 enc = "d:" + v.toGMTString();
15262 }else if(v instanceof Array){
15264 for(var i = 0, len = v.length; i < len; i++){
15265 flat += this.encodeValue(v[i]);
15271 }else if(typeof v == "object"){
15274 if(typeof v[key] != "function"){
15275 flat += key + "=" + this.encodeValue(v[key]) + "^";
15278 enc = "o:" + flat.substring(0, flat.length-1);
15282 return escape(enc);
15288 * Ext JS Library 1.1.1
15289 * Copyright(c) 2006-2007, Ext JS, LLC.
15291 * Originally Released Under LGPL - original licence link has changed is not relivant.
15294 * <script type="text/javascript">
15297 * @class Roo.state.Manager
15298 * This is the global state manager. By default all components that are "state aware" check this class
15299 * for state information if you don't pass them a custom state provider. In order for this class
15300 * to be useful, it must be initialized with a provider when your application initializes.
15302 // in your initialization function
15304 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15306 // supposed you have a {@link Roo.BorderLayout}
15307 var layout = new Roo.BorderLayout(...);
15308 layout.restoreState();
15309 // or a {Roo.BasicDialog}
15310 var dialog = new Roo.BasicDialog(...);
15311 dialog.restoreState();
15315 Roo.state.Manager = function(){
15316 var provider = new Roo.state.Provider();
15320 * Configures the default state provider for your application
15321 * @param {Provider} stateProvider The state provider to set
15323 setProvider : function(stateProvider){
15324 provider = stateProvider;
15328 * Returns the current value for a key
15329 * @param {String} name The key name
15330 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15331 * @return {Mixed} The state data
15333 get : function(key, defaultValue){
15334 return provider.get(key, defaultValue);
15338 * Sets the value for a key
15339 * @param {String} name The key name
15340 * @param {Mixed} value The state data
15342 set : function(key, value){
15343 provider.set(key, value);
15347 * Clears a value from the state
15348 * @param {String} name The key name
15350 clear : function(key){
15351 provider.clear(key);
15355 * Gets the currently configured state provider
15356 * @return {Provider} The state provider
15358 getProvider : function(){
15365 * Ext JS Library 1.1.1
15366 * Copyright(c) 2006-2007, Ext JS, LLC.
15368 * Originally Released Under LGPL - original licence link has changed is not relivant.
15371 * <script type="text/javascript">
15374 * @class Roo.state.CookieProvider
15375 * @extends Roo.state.Provider
15376 * The default Provider implementation which saves state via cookies.
15379 var cp = new Roo.state.CookieProvider({
15381 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15382 domain: "roojs.com"
15384 Roo.state.Manager.setProvider(cp);
15386 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15387 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15388 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15389 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15390 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15391 * domain the page is running on including the 'www' like 'www.roojs.com')
15392 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15394 * Create a new CookieProvider
15395 * @param {Object} config The configuration object
15397 Roo.state.CookieProvider = function(config){
15398 Roo.state.CookieProvider.superclass.constructor.call(this);
15400 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15401 this.domain = null;
15402 this.secure = false;
15403 Roo.apply(this, config);
15404 this.state = this.readCookies();
15407 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15409 set : function(name, value){
15410 if(typeof value == "undefined" || value === null){
15414 this.setCookie(name, value);
15415 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15419 clear : function(name){
15420 this.clearCookie(name);
15421 Roo.state.CookieProvider.superclass.clear.call(this, name);
15425 readCookies : function(){
15427 var c = document.cookie + ";";
15428 var re = /\s?(.*?)=(.*?);/g;
15430 while((matches = re.exec(c)) != null){
15431 var name = matches[1];
15432 var value = matches[2];
15433 if(name && name.substring(0,3) == "ys-"){
15434 cookies[name.substr(3)] = this.decodeValue(value);
15441 setCookie : function(name, value){
15442 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15443 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15444 ((this.path == null) ? "" : ("; path=" + this.path)) +
15445 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15446 ((this.secure == true) ? "; secure" : "");
15450 clearCookie : function(name){
15451 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15452 ((this.path == null) ? "" : ("; path=" + this.path)) +
15453 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15454 ((this.secure == true) ? "; secure" : "");
15458 * Ext JS Library 1.1.1
15459 * Copyright(c) 2006-2007, Ext JS, LLC.
15461 * Originally Released Under LGPL - original licence link has changed is not relivant.
15464 * <script type="text/javascript">
15469 * @class Roo.ComponentMgr
15470 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15473 Roo.ComponentMgr = function(){
15474 var all = new Roo.util.MixedCollection();
15478 * Registers a component.
15479 * @param {Roo.Component} c The component
15481 register : function(c){
15486 * Unregisters a component.
15487 * @param {Roo.Component} c The component
15489 unregister : function(c){
15494 * Returns a component by id
15495 * @param {String} id The component id
15497 get : function(id){
15498 return all.get(id);
15502 * Registers a function that will be called when a specified component is added to ComponentMgr
15503 * @param {String} id The component id
15504 * @param {Funtction} fn The callback function
15505 * @param {Object} scope The scope of the callback
15507 onAvailable : function(id, fn, scope){
15508 all.on("add", function(index, o){
15510 fn.call(scope || o, o);
15511 all.un("add", fn, scope);
15518 * Ext JS Library 1.1.1
15519 * Copyright(c) 2006-2007, Ext JS, LLC.
15521 * Originally Released Under LGPL - original licence link has changed is not relivant.
15524 * <script type="text/javascript">
15528 * @class Roo.Component
15529 * @extends Roo.util.Observable
15530 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15531 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15532 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15533 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15534 * All visual components (widgets) that require rendering into a layout should subclass Component.
15536 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15537 * 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
15538 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15540 Roo.Component = function(config){
15541 config = config || {};
15542 if(config.tagName || config.dom || typeof config == "string"){ // element object
15543 config = {el: config, id: config.id || config};
15545 this.initialConfig = config;
15547 Roo.apply(this, config);
15551 * Fires after the component is disabled.
15552 * @param {Roo.Component} this
15557 * Fires after the component is enabled.
15558 * @param {Roo.Component} this
15562 * @event beforeshow
15563 * Fires before the component is shown. Return false to stop the show.
15564 * @param {Roo.Component} this
15569 * Fires after the component is shown.
15570 * @param {Roo.Component} this
15574 * @event beforehide
15575 * Fires before the component is hidden. Return false to stop the hide.
15576 * @param {Roo.Component} this
15581 * Fires after the component is hidden.
15582 * @param {Roo.Component} this
15586 * @event beforerender
15587 * Fires before the component is rendered. Return false to stop the render.
15588 * @param {Roo.Component} this
15590 beforerender : true,
15593 * Fires after the component is rendered.
15594 * @param {Roo.Component} this
15598 * @event beforedestroy
15599 * Fires before the component is destroyed. Return false to stop the destroy.
15600 * @param {Roo.Component} this
15602 beforedestroy : true,
15605 * Fires after the component is destroyed.
15606 * @param {Roo.Component} this
15611 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15613 Roo.ComponentMgr.register(this);
15614 Roo.Component.superclass.constructor.call(this);
15615 this.initComponent();
15616 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15617 this.render(this.renderTo);
15618 delete this.renderTo;
15623 Roo.Component.AUTO_ID = 1000;
15625 Roo.extend(Roo.Component, Roo.util.Observable, {
15627 * @scope Roo.Component.prototype
15629 * true if this component is hidden. Read-only.
15634 * true if this component is disabled. Read-only.
15639 * true if this component has been rendered. Read-only.
15643 /** @cfg {String} disableClass
15644 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15646 disabledClass : "x-item-disabled",
15647 /** @cfg {Boolean} allowDomMove
15648 * Whether the component can move the Dom node when rendering (defaults to true).
15650 allowDomMove : true,
15651 /** @cfg {String} hideMode (display|visibility)
15652 * How this component should hidden. Supported values are
15653 * "visibility" (css visibility), "offsets" (negative offset position) and
15654 * "display" (css display) - defaults to "display".
15656 hideMode: 'display',
15659 ctype : "Roo.Component",
15662 * @cfg {String} actionMode
15663 * which property holds the element that used for hide() / show() / disable() / enable()
15664 * default is 'el' for forms you probably want to set this to fieldEl
15669 getActionEl : function(){
15670 return this[this.actionMode];
15673 initComponent : Roo.emptyFn,
15675 * If this is a lazy rendering component, render it to its container element.
15676 * @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.
15678 render : function(container, position){
15684 if(this.fireEvent("beforerender", this) === false){
15688 if(!container && this.el){
15689 this.el = Roo.get(this.el);
15690 container = this.el.dom.parentNode;
15691 this.allowDomMove = false;
15693 this.container = Roo.get(container);
15694 this.rendered = true;
15695 if(position !== undefined){
15696 if(typeof position == 'number'){
15697 position = this.container.dom.childNodes[position];
15699 position = Roo.getDom(position);
15702 this.onRender(this.container, position || null);
15704 this.el.addClass(this.cls);
15708 this.el.applyStyles(this.style);
15711 this.fireEvent("render", this);
15712 this.afterRender(this.container);
15725 // default function is not really useful
15726 onRender : function(ct, position){
15728 this.el = Roo.get(this.el);
15729 if(this.allowDomMove !== false){
15730 ct.dom.insertBefore(this.el.dom, position);
15736 getAutoCreate : function(){
15737 var cfg = typeof this.autoCreate == "object" ?
15738 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15739 if(this.id && !cfg.id){
15746 afterRender : Roo.emptyFn,
15749 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15750 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15752 destroy : function(){
15753 if(this.fireEvent("beforedestroy", this) !== false){
15754 this.purgeListeners();
15755 this.beforeDestroy();
15757 this.el.removeAllListeners();
15759 if(this.actionMode == "container"){
15760 this.container.remove();
15764 Roo.ComponentMgr.unregister(this);
15765 this.fireEvent("destroy", this);
15770 beforeDestroy : function(){
15775 onDestroy : function(){
15780 * Returns the underlying {@link Roo.Element}.
15781 * @return {Roo.Element} The element
15783 getEl : function(){
15788 * Returns the id of this component.
15791 getId : function(){
15796 * Try to focus this component.
15797 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15798 * @return {Roo.Component} this
15800 focus : function(selectText){
15803 if(selectText === true){
15804 this.el.dom.select();
15819 * Disable this component.
15820 * @return {Roo.Component} this
15822 disable : function(){
15826 this.disabled = true;
15827 this.fireEvent("disable", this);
15832 onDisable : function(){
15833 this.getActionEl().addClass(this.disabledClass);
15834 this.el.dom.disabled = true;
15838 * Enable this component.
15839 * @return {Roo.Component} this
15841 enable : function(){
15845 this.disabled = false;
15846 this.fireEvent("enable", this);
15851 onEnable : function(){
15852 this.getActionEl().removeClass(this.disabledClass);
15853 this.el.dom.disabled = false;
15857 * Convenience function for setting disabled/enabled by boolean.
15858 * @param {Boolean} disabled
15860 setDisabled : function(disabled){
15861 this[disabled ? "disable" : "enable"]();
15865 * Show this component.
15866 * @return {Roo.Component} this
15869 if(this.fireEvent("beforeshow", this) !== false){
15870 this.hidden = false;
15874 this.fireEvent("show", this);
15880 onShow : function(){
15881 var ae = this.getActionEl();
15882 if(this.hideMode == 'visibility'){
15883 ae.dom.style.visibility = "visible";
15884 }else if(this.hideMode == 'offsets'){
15885 ae.removeClass('x-hidden');
15887 ae.dom.style.display = "";
15892 * Hide this component.
15893 * @return {Roo.Component} this
15896 if(this.fireEvent("beforehide", this) !== false){
15897 this.hidden = true;
15901 this.fireEvent("hide", this);
15907 onHide : function(){
15908 var ae = this.getActionEl();
15909 if(this.hideMode == 'visibility'){
15910 ae.dom.style.visibility = "hidden";
15911 }else if(this.hideMode == 'offsets'){
15912 ae.addClass('x-hidden');
15914 ae.dom.style.display = "none";
15919 * Convenience function to hide or show this component by boolean.
15920 * @param {Boolean} visible True to show, false to hide
15921 * @return {Roo.Component} this
15923 setVisible: function(visible){
15933 * Returns true if this component is visible.
15935 isVisible : function(){
15936 return this.getActionEl().isVisible();
15939 cloneConfig : function(overrides){
15940 overrides = overrides || {};
15941 var id = overrides.id || Roo.id();
15942 var cfg = Roo.applyIf(overrides, this.initialConfig);
15943 cfg.id = id; // prevent dup id
15944 return new this.constructor(cfg);
15948 * Ext JS Library 1.1.1
15949 * Copyright(c) 2006-2007, Ext JS, LLC.
15951 * Originally Released Under LGPL - original licence link has changed is not relivant.
15954 * <script type="text/javascript">
15958 * @class Roo.BoxComponent
15959 * @extends Roo.Component
15960 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15961 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15962 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
15963 * layout containers.
15965 * @param {Roo.Element/String/Object} config The configuration options.
15967 Roo.BoxComponent = function(config){
15968 Roo.Component.call(this, config);
15972 * Fires after the component is resized.
15973 * @param {Roo.Component} this
15974 * @param {Number} adjWidth The box-adjusted width that was set
15975 * @param {Number} adjHeight The box-adjusted height that was set
15976 * @param {Number} rawWidth The width that was originally specified
15977 * @param {Number} rawHeight The height that was originally specified
15982 * Fires after the component is moved.
15983 * @param {Roo.Component} this
15984 * @param {Number} x The new x position
15985 * @param {Number} y The new y position
15991 Roo.extend(Roo.BoxComponent, Roo.Component, {
15992 // private, set in afterRender to signify that the component has been rendered
15994 // private, used to defer height settings to subclasses
15995 deferHeight: false,
15996 /** @cfg {Number} width
15997 * width (optional) size of component
15999 /** @cfg {Number} height
16000 * height (optional) size of component
16004 * Sets the width and height of the component. This method fires the resize event. This method can accept
16005 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16006 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16007 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16008 * @return {Roo.BoxComponent} this
16010 setSize : function(w, h){
16011 // support for standard size objects
16012 if(typeof w == 'object'){
16017 if(!this.boxReady){
16023 // prevent recalcs when not needed
16024 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16027 this.lastSize = {width: w, height: h};
16029 var adj = this.adjustSize(w, h);
16030 var aw = adj.width, ah = adj.height;
16031 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16032 var rz = this.getResizeEl();
16033 if(!this.deferHeight && aw !== undefined && ah !== undefined){
16034 rz.setSize(aw, ah);
16035 }else if(!this.deferHeight && ah !== undefined){
16037 }else if(aw !== undefined){
16040 this.onResize(aw, ah, w, h);
16041 this.fireEvent('resize', this, aw, ah, w, h);
16047 * Gets the current size of the component's underlying element.
16048 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16050 getSize : function(){
16051 return this.el.getSize();
16055 * Gets the current XY position of the component's underlying element.
16056 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16057 * @return {Array} The XY position of the element (e.g., [100, 200])
16059 getPosition : function(local){
16060 if(local === true){
16061 return [this.el.getLeft(true), this.el.getTop(true)];
16063 return this.xy || this.el.getXY();
16067 * Gets the current box measurements of the component's underlying element.
16068 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16069 * @returns {Object} box An object in the format {x, y, width, height}
16071 getBox : function(local){
16072 var s = this.el.getSize();
16074 s.x = this.el.getLeft(true);
16075 s.y = this.el.getTop(true);
16077 var xy = this.xy || this.el.getXY();
16085 * Sets the current box measurements of the component's underlying element.
16086 * @param {Object} box An object in the format {x, y, width, height}
16087 * @returns {Roo.BoxComponent} this
16089 updateBox : function(box){
16090 this.setSize(box.width, box.height);
16091 this.setPagePosition(box.x, box.y);
16096 getResizeEl : function(){
16097 return this.resizeEl || this.el;
16101 getPositionEl : function(){
16102 return this.positionEl || this.el;
16106 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16107 * This method fires the move event.
16108 * @param {Number} left The new left
16109 * @param {Number} top The new top
16110 * @returns {Roo.BoxComponent} this
16112 setPosition : function(x, y){
16115 if(!this.boxReady){
16118 var adj = this.adjustPosition(x, y);
16119 var ax = adj.x, ay = adj.y;
16121 var el = this.getPositionEl();
16122 if(ax !== undefined || ay !== undefined){
16123 if(ax !== undefined && ay !== undefined){
16124 el.setLeftTop(ax, ay);
16125 }else if(ax !== undefined){
16127 }else if(ay !== undefined){
16130 this.onPosition(ax, ay);
16131 this.fireEvent('move', this, ax, ay);
16137 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16138 * This method fires the move event.
16139 * @param {Number} x The new x position
16140 * @param {Number} y The new y position
16141 * @returns {Roo.BoxComponent} this
16143 setPagePosition : function(x, y){
16146 if(!this.boxReady){
16149 if(x === undefined || y === undefined){ // cannot translate undefined points
16152 var p = this.el.translatePoints(x, y);
16153 this.setPosition(p.left, p.top);
16158 onRender : function(ct, position){
16159 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16161 this.resizeEl = Roo.get(this.resizeEl);
16163 if(this.positionEl){
16164 this.positionEl = Roo.get(this.positionEl);
16169 afterRender : function(){
16170 Roo.BoxComponent.superclass.afterRender.call(this);
16171 this.boxReady = true;
16172 this.setSize(this.width, this.height);
16173 if(this.x || this.y){
16174 this.setPosition(this.x, this.y);
16176 if(this.pageX || this.pageY){
16177 this.setPagePosition(this.pageX, this.pageY);
16182 * Force the component's size to recalculate based on the underlying element's current height and width.
16183 * @returns {Roo.BoxComponent} this
16185 syncSize : function(){
16186 delete this.lastSize;
16187 this.setSize(this.el.getWidth(), this.el.getHeight());
16192 * Called after the component is resized, this method is empty by default but can be implemented by any
16193 * subclass that needs to perform custom logic after a resize occurs.
16194 * @param {Number} adjWidth The box-adjusted width that was set
16195 * @param {Number} adjHeight The box-adjusted height that was set
16196 * @param {Number} rawWidth The width that was originally specified
16197 * @param {Number} rawHeight The height that was originally specified
16199 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16204 * Called after the component is moved, this method is empty by default but can be implemented by any
16205 * subclass that needs to perform custom logic after a move occurs.
16206 * @param {Number} x The new x position
16207 * @param {Number} y The new y position
16209 onPosition : function(x, y){
16214 adjustSize : function(w, h){
16215 if(this.autoWidth){
16218 if(this.autoHeight){
16221 return {width : w, height: h};
16225 adjustPosition : function(x, y){
16226 return {x : x, y: y};
16230 * Ext JS Library 1.1.1
16231 * Copyright(c) 2006-2007, Ext JS, LLC.
16233 * Originally Released Under LGPL - original licence link has changed is not relivant.
16236 * <script type="text/javascript">
16241 * @extends Roo.Element
16242 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16243 * automatic maintaining of shadow/shim positions.
16244 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16245 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16246 * you can pass a string with a CSS class name. False turns off the shadow.
16247 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16248 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16249 * @cfg {String} cls CSS class to add to the element
16250 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16251 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16253 * @param {Object} config An object with config options.
16254 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16257 Roo.Layer = function(config, existingEl){
16258 config = config || {};
16259 var dh = Roo.DomHelper;
16260 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16262 this.dom = Roo.getDom(existingEl);
16265 var o = config.dh || {tag: "div", cls: "x-layer"};
16266 this.dom = dh.append(pel, o);
16269 this.addClass(config.cls);
16271 this.constrain = config.constrain !== false;
16272 this.visibilityMode = Roo.Element.VISIBILITY;
16274 this.id = this.dom.id = config.id;
16276 this.id = Roo.id(this.dom);
16278 this.zindex = config.zindex || this.getZIndex();
16279 this.position("absolute", this.zindex);
16281 this.shadowOffset = config.shadowOffset || 4;
16282 this.shadow = new Roo.Shadow({
16283 offset : this.shadowOffset,
16284 mode : config.shadow
16287 this.shadowOffset = 0;
16289 this.useShim = config.shim !== false && Roo.useShims;
16290 this.useDisplay = config.useDisplay;
16294 var supr = Roo.Element.prototype;
16296 // shims are shared among layer to keep from having 100 iframes
16299 Roo.extend(Roo.Layer, Roo.Element, {
16301 getZIndex : function(){
16302 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16305 getShim : function(){
16312 var shim = shims.shift();
16314 shim = this.createShim();
16315 shim.enableDisplayMode('block');
16316 shim.dom.style.display = 'none';
16317 shim.dom.style.visibility = 'visible';
16319 var pn = this.dom.parentNode;
16320 if(shim.dom.parentNode != pn){
16321 pn.insertBefore(shim.dom, this.dom);
16323 shim.setStyle('z-index', this.getZIndex()-2);
16328 hideShim : function(){
16330 this.shim.setDisplayed(false);
16331 shims.push(this.shim);
16336 disableShadow : function(){
16338 this.shadowDisabled = true;
16339 this.shadow.hide();
16340 this.lastShadowOffset = this.shadowOffset;
16341 this.shadowOffset = 0;
16345 enableShadow : function(show){
16347 this.shadowDisabled = false;
16348 this.shadowOffset = this.lastShadowOffset;
16349 delete this.lastShadowOffset;
16357 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16358 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16359 sync : function(doShow){
16360 var sw = this.shadow;
16361 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16362 var sh = this.getShim();
16364 var w = this.getWidth(),
16365 h = this.getHeight();
16367 var l = this.getLeft(true),
16368 t = this.getTop(true);
16370 if(sw && !this.shadowDisabled){
16371 if(doShow && !sw.isVisible()){
16374 sw.realign(l, t, w, h);
16380 // fit the shim behind the shadow, so it is shimmed too
16381 var a = sw.adjusts, s = sh.dom.style;
16382 s.left = (Math.min(l, l+a.l))+"px";
16383 s.top = (Math.min(t, t+a.t))+"px";
16384 s.width = (w+a.w)+"px";
16385 s.height = (h+a.h)+"px";
16392 sh.setLeftTop(l, t);
16399 destroy : function(){
16402 this.shadow.hide();
16404 this.removeAllListeners();
16405 var pn = this.dom.parentNode;
16407 pn.removeChild(this.dom);
16409 Roo.Element.uncache(this.id);
16412 remove : function(){
16417 beginUpdate : function(){
16418 this.updating = true;
16422 endUpdate : function(){
16423 this.updating = false;
16428 hideUnders : function(negOffset){
16430 this.shadow.hide();
16436 constrainXY : function(){
16437 if(this.constrain){
16438 var vw = Roo.lib.Dom.getViewWidth(),
16439 vh = Roo.lib.Dom.getViewHeight();
16440 var s = Roo.get(document).getScroll();
16442 var xy = this.getXY();
16443 var x = xy[0], y = xy[1];
16444 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16445 // only move it if it needs it
16447 // first validate right/bottom
16448 if((x + w) > vw+s.left){
16449 x = vw - w - this.shadowOffset;
16452 if((y + h) > vh+s.top){
16453 y = vh - h - this.shadowOffset;
16456 // then make sure top/left isn't negative
16467 var ay = this.avoidY;
16468 if(y <= ay && (y+h) >= ay){
16474 supr.setXY.call(this, xy);
16480 isVisible : function(){
16481 return this.visible;
16485 showAction : function(){
16486 this.visible = true; // track visibility to prevent getStyle calls
16487 if(this.useDisplay === true){
16488 this.setDisplayed("");
16489 }else if(this.lastXY){
16490 supr.setXY.call(this, this.lastXY);
16491 }else if(this.lastLT){
16492 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16497 hideAction : function(){
16498 this.visible = false;
16499 if(this.useDisplay === true){
16500 this.setDisplayed(false);
16502 this.setLeftTop(-10000,-10000);
16506 // overridden Element method
16507 setVisible : function(v, a, d, c, e){
16512 var cb = function(){
16517 }.createDelegate(this);
16518 supr.setVisible.call(this, true, true, d, cb, e);
16521 this.hideUnders(true);
16530 }.createDelegate(this);
16532 supr.setVisible.call(this, v, a, d, cb, e);
16541 storeXY : function(xy){
16542 delete this.lastLT;
16546 storeLeftTop : function(left, top){
16547 delete this.lastXY;
16548 this.lastLT = [left, top];
16552 beforeFx : function(){
16553 this.beforeAction();
16554 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16558 afterFx : function(){
16559 Roo.Layer.superclass.afterFx.apply(this, arguments);
16560 this.sync(this.isVisible());
16564 beforeAction : function(){
16565 if(!this.updating && this.shadow){
16566 this.shadow.hide();
16570 // overridden Element method
16571 setLeft : function(left){
16572 this.storeLeftTop(left, this.getTop(true));
16573 supr.setLeft.apply(this, arguments);
16577 setTop : function(top){
16578 this.storeLeftTop(this.getLeft(true), top);
16579 supr.setTop.apply(this, arguments);
16583 setLeftTop : function(left, top){
16584 this.storeLeftTop(left, top);
16585 supr.setLeftTop.apply(this, arguments);
16589 setXY : function(xy, a, d, c, e){
16591 this.beforeAction();
16593 var cb = this.createCB(c);
16594 supr.setXY.call(this, xy, a, d, cb, e);
16601 createCB : function(c){
16612 // overridden Element method
16613 setX : function(x, a, d, c, e){
16614 this.setXY([x, this.getY()], a, d, c, e);
16617 // overridden Element method
16618 setY : function(y, a, d, c, e){
16619 this.setXY([this.getX(), y], a, d, c, e);
16622 // overridden Element method
16623 setSize : function(w, h, a, d, c, e){
16624 this.beforeAction();
16625 var cb = this.createCB(c);
16626 supr.setSize.call(this, w, h, a, d, cb, e);
16632 // overridden Element method
16633 setWidth : function(w, a, d, c, e){
16634 this.beforeAction();
16635 var cb = this.createCB(c);
16636 supr.setWidth.call(this, w, a, d, cb, e);
16642 // overridden Element method
16643 setHeight : function(h, a, d, c, e){
16644 this.beforeAction();
16645 var cb = this.createCB(c);
16646 supr.setHeight.call(this, h, a, d, cb, e);
16652 // overridden Element method
16653 setBounds : function(x, y, w, h, a, d, c, e){
16654 this.beforeAction();
16655 var cb = this.createCB(c);
16657 this.storeXY([x, y]);
16658 supr.setXY.call(this, [x, y]);
16659 supr.setSize.call(this, w, h, a, d, cb, e);
16662 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16668 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16669 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16670 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16671 * @param {Number} zindex The new z-index to set
16672 * @return {this} The Layer
16674 setZIndex : function(zindex){
16675 this.zindex = zindex;
16676 this.setStyle("z-index", zindex + 2);
16678 this.shadow.setZIndex(zindex + 1);
16681 this.shim.setStyle("z-index", zindex);
16686 * Original code for Roojs - LGPL
16687 * <script type="text/javascript">
16691 * @class Roo.XComponent
16692 * A delayed Element creator...
16693 * Or a way to group chunks of interface together.
16694 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16695 * used in conjunction with XComponent.build() it will create an instance of each element,
16696 * then call addxtype() to build the User interface.
16698 * Mypart.xyx = new Roo.XComponent({
16700 parent : 'Mypart.xyz', // empty == document.element.!!
16704 disabled : function() {}
16706 tree : function() { // return an tree of xtype declared components
16710 xtype : 'NestedLayoutPanel',
16717 * It can be used to build a big heiracy, with parent etc.
16718 * or you can just use this to render a single compoent to a dom element
16719 * MYPART.render(Roo.Element | String(id) | dom_element )
16726 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16727 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16729 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16731 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16732 * - if mulitple topModules exist, the last one is defined as the top module.
16736 * When the top level or multiple modules are to embedded into a existing HTML page,
16737 * the parent element can container '#id' of the element where the module will be drawn.
16741 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16742 * it relies more on a include mechanism, where sub modules are included into an outer page.
16743 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16745 * Bootstrap Roo Included elements
16747 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16748 * hence confusing the component builder as it thinks there are multiple top level elements.
16750 * String Over-ride & Translations
16752 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16753 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16754 * are needed. @see Roo.XComponent.overlayString
16758 * @extends Roo.util.Observable
16760 * @param cfg {Object} configuration of component
16763 Roo.XComponent = function(cfg) {
16764 Roo.apply(this, cfg);
16768 * Fires when this the componnt is built
16769 * @param {Roo.XComponent} c the component
16774 this.region = this.region || 'center'; // default..
16775 Roo.XComponent.register(this);
16776 this.modules = false;
16777 this.el = false; // where the layout goes..
16781 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16784 * The created element (with Roo.factory())
16785 * @type {Roo.Layout}
16791 * for BC - use el in new code
16792 * @type {Roo.Layout}
16798 * for BC - use el in new code
16799 * @type {Roo.Layout}
16804 * @cfg {Function|boolean} disabled
16805 * If this module is disabled by some rule, return true from the funtion
16810 * @cfg {String} parent
16811 * Name of parent element which it get xtype added to..
16816 * @cfg {String} order
16817 * Used to set the order in which elements are created (usefull for multiple tabs)
16822 * @cfg {String} name
16823 * String to display while loading.
16827 * @cfg {String} region
16828 * Region to render component to (defaults to center)
16833 * @cfg {Array} items
16834 * A single item array - the first element is the root of the tree..
16835 * It's done this way to stay compatible with the Xtype system...
16841 * The method that retuns the tree of parts that make up this compoennt
16848 * render element to dom or tree
16849 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16852 render : function(el)
16856 var hp = this.parent ? 1 : 0;
16857 Roo.debug && Roo.log(this);
16859 var tree = this._tree ? this._tree() : this.tree();
16862 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16863 // if parent is a '#.....' string, then let's use that..
16864 var ename = this.parent.substr(1);
16865 this.parent = false;
16866 Roo.debug && Roo.log(ename);
16868 case 'bootstrap-body':
16869 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16870 // this is the BorderLayout standard?
16871 this.parent = { el : true };
16874 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16875 // need to insert stuff...
16877 el : new Roo.bootstrap.layout.Border({
16878 el : document.body,
16884 tabPosition: 'top',
16885 //resizeTabs: true,
16886 alwaysShowTabs: true,
16896 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16897 this.parent = { el : new Roo.bootstrap.Body() };
16898 Roo.debug && Roo.log("setting el to doc body");
16901 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16905 this.parent = { el : true};
16908 el = Roo.get(ename);
16909 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16910 this.parent = { el : true};
16917 if (!el && !this.parent) {
16918 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16923 Roo.debug && Roo.log("EL:");
16924 Roo.debug && Roo.log(el);
16925 Roo.debug && Roo.log("this.parent.el:");
16926 Roo.debug && Roo.log(this.parent.el);
16929 // altertive root elements ??? - we need a better way to indicate these.
16930 var is_alt = Roo.XComponent.is_alt ||
16931 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16932 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16933 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16937 if (!this.parent && is_alt) {
16938 //el = Roo.get(document.body);
16939 this.parent = { el : true };
16944 if (!this.parent) {
16946 Roo.debug && Roo.log("no parent - creating one");
16948 el = el ? Roo.get(el) : false;
16950 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16953 el : new Roo.bootstrap.layout.Border({
16954 el: el || document.body,
16960 tabPosition: 'top',
16961 //resizeTabs: true,
16962 alwaysShowTabs: false,
16965 overflow: 'visible'
16971 // it's a top level one..
16973 el : new Roo.BorderLayout(el || document.body, {
16978 tabPosition: 'top',
16979 //resizeTabs: true,
16980 alwaysShowTabs: el && hp? false : true,
16981 hideTabs: el || !hp ? true : false,
16989 if (!this.parent.el) {
16990 // probably an old style ctor, which has been disabled.
16994 // The 'tree' method is '_tree now'
16996 tree.region = tree.region || this.region;
16997 var is_body = false;
16998 if (this.parent.el === true) {
16999 // bootstrap... - body..
17003 this.parent.el = Roo.factory(tree);
17007 this.el = this.parent.el.addxtype(tree, undefined, is_body);
17008 this.fireEvent('built', this);
17010 this.panel = this.el;
17011 this.layout = this.panel.layout;
17012 this.parentLayout = this.parent.layout || false;
17018 Roo.apply(Roo.XComponent, {
17020 * @property hideProgress
17021 * true to disable the building progress bar.. usefull on single page renders.
17024 hideProgress : false,
17026 * @property buildCompleted
17027 * True when the builder has completed building the interface.
17030 buildCompleted : false,
17033 * @property topModule
17034 * the upper most module - uses document.element as it's constructor.
17041 * @property modules
17042 * array of modules to be created by registration system.
17043 * @type {Array} of Roo.XComponent
17048 * @property elmodules
17049 * array of modules to be created by which use #ID
17050 * @type {Array} of Roo.XComponent
17057 * Is an alternative Root - normally used by bootstrap or other systems,
17058 * where the top element in the tree can wrap 'body'
17059 * @type {boolean} (default false)
17064 * @property build_from_html
17065 * Build elements from html - used by bootstrap HTML stuff
17066 * - this is cleared after build is completed
17067 * @type {boolean} (default false)
17070 build_from_html : false,
17072 * Register components to be built later.
17074 * This solves the following issues
17075 * - Building is not done on page load, but after an authentication process has occured.
17076 * - Interface elements are registered on page load
17077 * - Parent Interface elements may not be loaded before child, so this handles that..
17084 module : 'Pman.Tab.projectMgr',
17086 parent : 'Pman.layout',
17087 disabled : false, // or use a function..
17090 * * @param {Object} details about module
17092 register : function(obj) {
17094 Roo.XComponent.event.fireEvent('register', obj);
17095 switch(typeof(obj.disabled) ) {
17101 if ( obj.disabled() ) {
17107 if (obj.disabled || obj.region == '#disabled') {
17113 this.modules.push(obj);
17117 * convert a string to an object..
17118 * eg. 'AAA.BBB' -> finds AAA.BBB
17122 toObject : function(str)
17124 if (!str || typeof(str) == 'object') {
17127 if (str.substring(0,1) == '#') {
17131 var ar = str.split('.');
17136 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17138 throw "Module not found : " + str;
17142 throw "Module not found : " + str;
17144 Roo.each(ar, function(e) {
17145 if (typeof(o[e]) == 'undefined') {
17146 throw "Module not found : " + str;
17157 * move modules into their correct place in the tree..
17160 preBuild : function ()
17163 Roo.each(this.modules , function (obj)
17165 Roo.XComponent.event.fireEvent('beforebuild', obj);
17167 var opar = obj.parent;
17169 obj.parent = this.toObject(opar);
17171 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17176 Roo.debug && Roo.log("GOT top level module");
17177 Roo.debug && Roo.log(obj);
17178 obj.modules = new Roo.util.MixedCollection(false,
17179 function(o) { return o.order + '' }
17181 this.topModule = obj;
17184 // parent is a string (usually a dom element name..)
17185 if (typeof(obj.parent) == 'string') {
17186 this.elmodules.push(obj);
17189 if (obj.parent.constructor != Roo.XComponent) {
17190 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17192 if (!obj.parent.modules) {
17193 obj.parent.modules = new Roo.util.MixedCollection(false,
17194 function(o) { return o.order + '' }
17197 if (obj.parent.disabled) {
17198 obj.disabled = true;
17200 obj.parent.modules.add(obj);
17205 * make a list of modules to build.
17206 * @return {Array} list of modules.
17209 buildOrder : function()
17212 var cmp = function(a,b) {
17213 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17215 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17216 throw "No top level modules to build";
17219 // make a flat list in order of modules to build.
17220 var mods = this.topModule ? [ this.topModule ] : [];
17223 // elmodules (is a list of DOM based modules )
17224 Roo.each(this.elmodules, function(e) {
17226 if (!this.topModule &&
17227 typeof(e.parent) == 'string' &&
17228 e.parent.substring(0,1) == '#' &&
17229 Roo.get(e.parent.substr(1))
17232 _this.topModule = e;
17238 // add modules to their parents..
17239 var addMod = function(m) {
17240 Roo.debug && Roo.log("build Order: add: " + m.name);
17243 if (m.modules && !m.disabled) {
17244 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17245 m.modules.keySort('ASC', cmp );
17246 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17248 m.modules.each(addMod);
17250 Roo.debug && Roo.log("build Order: no child modules");
17252 // not sure if this is used any more..
17254 m.finalize.name = m.name + " (clean up) ";
17255 mods.push(m.finalize);
17259 if (this.topModule && this.topModule.modules) {
17260 this.topModule.modules.keySort('ASC', cmp );
17261 this.topModule.modules.each(addMod);
17267 * Build the registered modules.
17268 * @param {Object} parent element.
17269 * @param {Function} optional method to call after module has been added.
17273 build : function(opts)
17276 if (typeof(opts) != 'undefined') {
17277 Roo.apply(this,opts);
17281 var mods = this.buildOrder();
17283 //this.allmods = mods;
17284 //Roo.debug && Roo.log(mods);
17286 if (!mods.length) { // should not happen
17287 throw "NO modules!!!";
17291 var msg = "Building Interface...";
17292 // flash it up as modal - so we store the mask!?
17293 if (!this.hideProgress && Roo.MessageBox) {
17294 Roo.MessageBox.show({ title: 'loading' });
17295 Roo.MessageBox.show({
17296 title: "Please wait...",
17306 var total = mods.length;
17309 var progressRun = function() {
17310 if (!mods.length) {
17311 Roo.debug && Roo.log('hide?');
17312 if (!this.hideProgress && Roo.MessageBox) {
17313 Roo.MessageBox.hide();
17315 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17317 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17323 var m = mods.shift();
17326 Roo.debug && Roo.log(m);
17327 // not sure if this is supported any more.. - modules that are are just function
17328 if (typeof(m) == 'function') {
17330 return progressRun.defer(10, _this);
17334 msg = "Building Interface " + (total - mods.length) +
17336 (m.name ? (' - ' + m.name) : '');
17337 Roo.debug && Roo.log(msg);
17338 if (!_this.hideProgress && Roo.MessageBox) {
17339 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17343 // is the module disabled?
17344 var disabled = (typeof(m.disabled) == 'function') ?
17345 m.disabled.call(m.module.disabled) : m.disabled;
17349 return progressRun(); // we do not update the display!
17357 // it's 10 on top level, and 1 on others??? why...
17358 return progressRun.defer(10, _this);
17361 progressRun.defer(1, _this);
17367 * Overlay a set of modified strings onto a component
17368 * This is dependant on our builder exporting the strings and 'named strings' elements.
17370 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17371 * @param {Object} associative array of 'named' string and it's new value.
17374 overlayStrings : function( component, strings )
17376 if (typeof(component['_named_strings']) == 'undefined') {
17377 throw "ERROR: component does not have _named_strings";
17379 for ( var k in strings ) {
17380 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17381 if (md !== false) {
17382 component['_strings'][md] = strings[k];
17384 Roo.log('could not find named string: ' + k + ' in');
17385 Roo.log(component);
17400 * wrapper for event.on - aliased later..
17401 * Typically use to register a event handler for register:
17403 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17412 Roo.XComponent.event = new Roo.util.Observable({
17416 * Fires when an Component is registered,
17417 * set the disable property on the Component to stop registration.
17418 * @param {Roo.XComponent} c the component being registerd.
17423 * @event beforebuild
17424 * Fires before each Component is built
17425 * can be used to apply permissions.
17426 * @param {Roo.XComponent} c the component being registerd.
17429 'beforebuild' : true,
17431 * @event buildcomplete
17432 * Fires on the top level element when all elements have been built
17433 * @param {Roo.XComponent} the top level component.
17435 'buildcomplete' : true
17440 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17443 * marked - a markdown parser
17444 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17445 * https://github.com/chjj/marked
17451 * Roo.Markdown - is a very crude wrapper around marked..
17455 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17457 * Note: move the sample code to the bottom of this
17458 * file before uncommenting it.
17463 Roo.Markdown.toHtml = function(text) {
17465 var c = new Roo.Markdown.marked.setOptions({
17466 renderer: new Roo.Markdown.marked.Renderer(),
17477 text = text.replace(/\\\n/g,' ');
17478 return Roo.Markdown.marked(text);
17483 // Wraps all "globals" so that the only thing
17484 // exposed is makeHtml().
17490 * eval:var:unescape
17498 var escape = function (html, encode) {
17500 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17501 .replace(/</g, '<')
17502 .replace(/>/g, '>')
17503 .replace(/"/g, '"')
17504 .replace(/'/g, ''');
17507 var unescape = function (html) {
17508 // explicitly match decimal, hex, and named HTML entities
17509 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17510 n = n.toLowerCase();
17511 if (n === 'colon') { return ':'; }
17512 if (n.charAt(0) === '#') {
17513 return n.charAt(1) === 'x'
17514 ? String.fromCharCode(parseInt(n.substring(2), 16))
17515 : String.fromCharCode(+n.substring(1));
17521 var replace = function (regex, opt) {
17522 regex = regex.source;
17524 return function self(name, val) {
17525 if (!name) { return new RegExp(regex, opt); }
17526 val = val.source || val;
17527 val = val.replace(/(^|[^\[])\^/g, '$1');
17528 regex = regex.replace(name, val);
17537 var noop = function () {}
17543 var merge = function (obj) {
17548 for (; i < arguments.length; i++) {
17549 target = arguments[i];
17550 for (key in target) {
17551 if (Object.prototype.hasOwnProperty.call(target, key)) {
17552 obj[key] = target[key];
17562 * Block-Level Grammar
17570 code: /^( {4}[^\n]+\n*)+/,
17572 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17573 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17575 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17576 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17577 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17578 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17579 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17581 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17585 block.bullet = /(?:[*+-]|\d+\.)/;
17586 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17587 block.item = replace(block.item, 'gm')
17588 (/bull/g, block.bullet)
17591 block.list = replace(block.list)
17592 (/bull/g, block.bullet)
17593 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17594 ('def', '\\n+(?=' + block.def.source + ')')
17597 block.blockquote = replace(block.blockquote)
17601 block._tag = '(?!(?:'
17602 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17603 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17604 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17606 block.html = replace(block.html)
17607 ('comment', /<!--[\s\S]*?-->/)
17608 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17609 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17610 (/tag/g, block._tag)
17613 block.paragraph = replace(block.paragraph)
17615 ('heading', block.heading)
17616 ('lheading', block.lheading)
17617 ('blockquote', block.blockquote)
17618 ('tag', '<' + block._tag)
17623 * Normal Block Grammar
17626 block.normal = merge({}, block);
17629 * GFM Block Grammar
17632 block.gfm = merge({}, block.normal, {
17633 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17635 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17638 block.gfm.paragraph = replace(block.paragraph)
17640 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17641 + block.list.source.replace('\\1', '\\3') + '|')
17645 * GFM + Tables Block Grammar
17648 block.tables = merge({}, block.gfm, {
17649 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17650 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17657 var Lexer = function (options) {
17659 this.tokens.links = {};
17660 this.options = options || marked.defaults;
17661 this.rules = block.normal;
17663 if (this.options.gfm) {
17664 if (this.options.tables) {
17665 this.rules = block.tables;
17667 this.rules = block.gfm;
17673 * Expose Block Rules
17676 Lexer.rules = block;
17679 * Static Lex Method
17682 Lexer.lex = function(src, options) {
17683 var lexer = new Lexer(options);
17684 return lexer.lex(src);
17691 Lexer.prototype.lex = function(src) {
17693 .replace(/\r\n|\r/g, '\n')
17694 .replace(/\t/g, ' ')
17695 .replace(/\u00a0/g, ' ')
17696 .replace(/\u2424/g, '\n');
17698 return this.token(src, true);
17705 Lexer.prototype.token = function(src, top, bq) {
17706 var src = src.replace(/^ +$/gm, '')
17719 if (cap = this.rules.newline.exec(src)) {
17720 src = src.substring(cap[0].length);
17721 if (cap[0].length > 1) {
17729 if (cap = this.rules.code.exec(src)) {
17730 src = src.substring(cap[0].length);
17731 cap = cap[0].replace(/^ {4}/gm, '');
17734 text: !this.options.pedantic
17735 ? cap.replace(/\n+$/, '')
17742 if (cap = this.rules.fences.exec(src)) {
17743 src = src.substring(cap[0].length);
17753 if (cap = this.rules.heading.exec(src)) {
17754 src = src.substring(cap[0].length);
17757 depth: cap[1].length,
17763 // table no leading pipe (gfm)
17764 if (top && (cap = this.rules.nptable.exec(src))) {
17765 src = src.substring(cap[0].length);
17769 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17770 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17771 cells: cap[3].replace(/\n$/, '').split('\n')
17774 for (i = 0; i < item.align.length; i++) {
17775 if (/^ *-+: *$/.test(item.align[i])) {
17776 item.align[i] = 'right';
17777 } else if (/^ *:-+: *$/.test(item.align[i])) {
17778 item.align[i] = 'center';
17779 } else if (/^ *:-+ *$/.test(item.align[i])) {
17780 item.align[i] = 'left';
17782 item.align[i] = null;
17786 for (i = 0; i < item.cells.length; i++) {
17787 item.cells[i] = item.cells[i].split(/ *\| */);
17790 this.tokens.push(item);
17796 if (cap = this.rules.lheading.exec(src)) {
17797 src = src.substring(cap[0].length);
17800 depth: cap[2] === '=' ? 1 : 2,
17807 if (cap = this.rules.hr.exec(src)) {
17808 src = src.substring(cap[0].length);
17816 if (cap = this.rules.blockquote.exec(src)) {
17817 src = src.substring(cap[0].length);
17820 type: 'blockquote_start'
17823 cap = cap[0].replace(/^ *> ?/gm, '');
17825 // Pass `top` to keep the current
17826 // "toplevel" state. This is exactly
17827 // how markdown.pl works.
17828 this.token(cap, top, true);
17831 type: 'blockquote_end'
17838 if (cap = this.rules.list.exec(src)) {
17839 src = src.substring(cap[0].length);
17843 type: 'list_start',
17844 ordered: bull.length > 1
17847 // Get each top-level item.
17848 cap = cap[0].match(this.rules.item);
17854 for (; i < l; i++) {
17857 // Remove the list item's bullet
17858 // so it is seen as the next token.
17859 space = item.length;
17860 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17862 // Outdent whatever the
17863 // list item contains. Hacky.
17864 if (~item.indexOf('\n ')) {
17865 space -= item.length;
17866 item = !this.options.pedantic
17867 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17868 : item.replace(/^ {1,4}/gm, '');
17871 // Determine whether the next list item belongs here.
17872 // Backpedal if it does not belong in this list.
17873 if (this.options.smartLists && i !== l - 1) {
17874 b = block.bullet.exec(cap[i + 1])[0];
17875 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17876 src = cap.slice(i + 1).join('\n') + src;
17881 // Determine whether item is loose or not.
17882 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17883 // for discount behavior.
17884 loose = next || /\n\n(?!\s*$)/.test(item);
17886 next = item.charAt(item.length - 1) === '\n';
17887 if (!loose) { loose = next; }
17892 ? 'loose_item_start'
17893 : 'list_item_start'
17897 this.token(item, false, bq);
17900 type: 'list_item_end'
17912 if (cap = this.rules.html.exec(src)) {
17913 src = src.substring(cap[0].length);
17915 type: this.options.sanitize
17918 pre: !this.options.sanitizer
17919 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17926 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17927 src = src.substring(cap[0].length);
17928 this.tokens.links[cap[1].toLowerCase()] = {
17936 if (top && (cap = this.rules.table.exec(src))) {
17937 src = src.substring(cap[0].length);
17941 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17942 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17943 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17946 for (i = 0; i < item.align.length; i++) {
17947 if (/^ *-+: *$/.test(item.align[i])) {
17948 item.align[i] = 'right';
17949 } else if (/^ *:-+: *$/.test(item.align[i])) {
17950 item.align[i] = 'center';
17951 } else if (/^ *:-+ *$/.test(item.align[i])) {
17952 item.align[i] = 'left';
17954 item.align[i] = null;
17958 for (i = 0; i < item.cells.length; i++) {
17959 item.cells[i] = item.cells[i]
17960 .replace(/^ *\| *| *\| *$/g, '')
17964 this.tokens.push(item);
17969 // top-level paragraph
17970 if (top && (cap = this.rules.paragraph.exec(src))) {
17971 src = src.substring(cap[0].length);
17974 text: cap[1].charAt(cap[1].length - 1) === '\n'
17975 ? cap[1].slice(0, -1)
17982 if (cap = this.rules.text.exec(src)) {
17983 // Top-level should never reach here.
17984 src = src.substring(cap[0].length);
17994 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17998 return this.tokens;
18002 * Inline-Level Grammar
18006 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18007 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18009 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18010 link: /^!?\[(inside)\]\(href\)/,
18011 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18012 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18013 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18014 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18015 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18016 br: /^ {2,}\n(?!\s*$)/,
18018 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18021 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18022 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18024 inline.link = replace(inline.link)
18025 ('inside', inline._inside)
18026 ('href', inline._href)
18029 inline.reflink = replace(inline.reflink)
18030 ('inside', inline._inside)
18034 * Normal Inline Grammar
18037 inline.normal = merge({}, inline);
18040 * Pedantic Inline Grammar
18043 inline.pedantic = merge({}, inline.normal, {
18044 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18045 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18049 * GFM Inline Grammar
18052 inline.gfm = merge({}, inline.normal, {
18053 escape: replace(inline.escape)('])', '~|])')(),
18054 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18055 del: /^~~(?=\S)([\s\S]*?\S)~~/,
18056 text: replace(inline.text)
18058 ('|', '|https?://|')
18063 * GFM + Line Breaks Inline Grammar
18066 inline.breaks = merge({}, inline.gfm, {
18067 br: replace(inline.br)('{2,}', '*')(),
18068 text: replace(inline.gfm.text)('{2,}', '*')()
18072 * Inline Lexer & Compiler
18075 var InlineLexer = function (links, options) {
18076 this.options = options || marked.defaults;
18077 this.links = links;
18078 this.rules = inline.normal;
18079 this.renderer = this.options.renderer || new Renderer;
18080 this.renderer.options = this.options;
18084 Error('Tokens array requires a `links` property.');
18087 if (this.options.gfm) {
18088 if (this.options.breaks) {
18089 this.rules = inline.breaks;
18091 this.rules = inline.gfm;
18093 } else if (this.options.pedantic) {
18094 this.rules = inline.pedantic;
18099 * Expose Inline Rules
18102 InlineLexer.rules = inline;
18105 * Static Lexing/Compiling Method
18108 InlineLexer.output = function(src, links, options) {
18109 var inline = new InlineLexer(links, options);
18110 return inline.output(src);
18117 InlineLexer.prototype.output = function(src) {
18126 if (cap = this.rules.escape.exec(src)) {
18127 src = src.substring(cap[0].length);
18133 if (cap = this.rules.autolink.exec(src)) {
18134 src = src.substring(cap[0].length);
18135 if (cap[2] === '@') {
18136 text = cap[1].charAt(6) === ':'
18137 ? this.mangle(cap[1].substring(7))
18138 : this.mangle(cap[1]);
18139 href = this.mangle('mailto:') + text;
18141 text = escape(cap[1]);
18144 out += this.renderer.link(href, null, text);
18149 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18150 src = src.substring(cap[0].length);
18151 text = escape(cap[1]);
18153 out += this.renderer.link(href, null, text);
18158 if (cap = this.rules.tag.exec(src)) {
18159 if (!this.inLink && /^<a /i.test(cap[0])) {
18160 this.inLink = true;
18161 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18162 this.inLink = false;
18164 src = src.substring(cap[0].length);
18165 out += this.options.sanitize
18166 ? this.options.sanitizer
18167 ? this.options.sanitizer(cap[0])
18174 if (cap = this.rules.link.exec(src)) {
18175 src = src.substring(cap[0].length);
18176 this.inLink = true;
18177 out += this.outputLink(cap, {
18181 this.inLink = false;
18186 if ((cap = this.rules.reflink.exec(src))
18187 || (cap = this.rules.nolink.exec(src))) {
18188 src = src.substring(cap[0].length);
18189 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18190 link = this.links[link.toLowerCase()];
18191 if (!link || !link.href) {
18192 out += cap[0].charAt(0);
18193 src = cap[0].substring(1) + src;
18196 this.inLink = true;
18197 out += this.outputLink(cap, link);
18198 this.inLink = false;
18203 if (cap = this.rules.strong.exec(src)) {
18204 src = src.substring(cap[0].length);
18205 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18210 if (cap = this.rules.em.exec(src)) {
18211 src = src.substring(cap[0].length);
18212 out += this.renderer.em(this.output(cap[2] || cap[1]));
18217 if (cap = this.rules.code.exec(src)) {
18218 src = src.substring(cap[0].length);
18219 out += this.renderer.codespan(escape(cap[2], true));
18224 if (cap = this.rules.br.exec(src)) {
18225 src = src.substring(cap[0].length);
18226 out += this.renderer.br();
18231 if (cap = this.rules.del.exec(src)) {
18232 src = src.substring(cap[0].length);
18233 out += this.renderer.del(this.output(cap[1]));
18238 if (cap = this.rules.text.exec(src)) {
18239 src = src.substring(cap[0].length);
18240 out += this.renderer.text(escape(this.smartypants(cap[0])));
18246 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18257 InlineLexer.prototype.outputLink = function(cap, link) {
18258 var href = escape(link.href)
18259 , title = link.title ? escape(link.title) : null;
18261 return cap[0].charAt(0) !== '!'
18262 ? this.renderer.link(href, title, this.output(cap[1]))
18263 : this.renderer.image(href, title, escape(cap[1]));
18267 * Smartypants Transformations
18270 InlineLexer.prototype.smartypants = function(text) {
18271 if (!this.options.smartypants) { return text; }
18274 .replace(/---/g, '\u2014')
18276 .replace(/--/g, '\u2013')
18278 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18279 // closing singles & apostrophes
18280 .replace(/'/g, '\u2019')
18282 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18284 .replace(/"/g, '\u201d')
18286 .replace(/\.{3}/g, '\u2026');
18293 InlineLexer.prototype.mangle = function(text) {
18294 if (!this.options.mangle) { return text; }
18300 for (; i < l; i++) {
18301 ch = text.charCodeAt(i);
18302 if (Math.random() > 0.5) {
18303 ch = 'x' + ch.toString(16);
18305 out += '&#' + ch + ';';
18316 * eval:var:Renderer
18319 var Renderer = function (options) {
18320 this.options = options || {};
18323 Renderer.prototype.code = function(code, lang, escaped) {
18324 if (this.options.highlight) {
18325 var out = this.options.highlight(code, lang);
18326 if (out != null && out !== code) {
18331 // hack!!! - it's already escapeD?
18336 return '<pre><code>'
18337 + (escaped ? code : escape(code, true))
18338 + '\n</code></pre>';
18341 return '<pre><code class="'
18342 + this.options.langPrefix
18343 + escape(lang, true)
18345 + (escaped ? code : escape(code, true))
18346 + '\n</code></pre>\n';
18349 Renderer.prototype.blockquote = function(quote) {
18350 return '<blockquote>\n' + quote + '</blockquote>\n';
18353 Renderer.prototype.html = function(html) {
18357 Renderer.prototype.heading = function(text, level, raw) {
18361 + this.options.headerPrefix
18362 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18370 Renderer.prototype.hr = function() {
18371 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18374 Renderer.prototype.list = function(body, ordered) {
18375 var type = ordered ? 'ol' : 'ul';
18376 return '<' + type + '>\n' + body + '</' + type + '>\n';
18379 Renderer.prototype.listitem = function(text) {
18380 return '<li>' + text + '</li>\n';
18383 Renderer.prototype.paragraph = function(text) {
18384 return '<p>' + text + '</p>\n';
18387 Renderer.prototype.table = function(header, body) {
18388 return '<table class="table table-striped">\n'
18398 Renderer.prototype.tablerow = function(content) {
18399 return '<tr>\n' + content + '</tr>\n';
18402 Renderer.prototype.tablecell = function(content, flags) {
18403 var type = flags.header ? 'th' : 'td';
18404 var tag = flags.align
18405 ? '<' + type + ' style="text-align:' + flags.align + '">'
18406 : '<' + type + '>';
18407 return tag + content + '</' + type + '>\n';
18410 // span level renderer
18411 Renderer.prototype.strong = function(text) {
18412 return '<strong>' + text + '</strong>';
18415 Renderer.prototype.em = function(text) {
18416 return '<em>' + text + '</em>';
18419 Renderer.prototype.codespan = function(text) {
18420 return '<code>' + text + '</code>';
18423 Renderer.prototype.br = function() {
18424 return this.options.xhtml ? '<br/>' : '<br>';
18427 Renderer.prototype.del = function(text) {
18428 return '<del>' + text + '</del>';
18431 Renderer.prototype.link = function(href, title, text) {
18432 if (this.options.sanitize) {
18434 var prot = decodeURIComponent(unescape(href))
18435 .replace(/[^\w:]/g, '')
18440 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18444 var out = '<a href="' + href + '"';
18446 out += ' title="' + title + '"';
18448 out += '>' + text + '</a>';
18452 Renderer.prototype.image = function(href, title, text) {
18453 var out = '<img src="' + href + '" alt="' + text + '"';
18455 out += ' title="' + title + '"';
18457 out += this.options.xhtml ? '/>' : '>';
18461 Renderer.prototype.text = function(text) {
18466 * Parsing & Compiling
18472 var Parser= function (options) {
18475 this.options = options || marked.defaults;
18476 this.options.renderer = this.options.renderer || new Renderer;
18477 this.renderer = this.options.renderer;
18478 this.renderer.options = this.options;
18482 * Static Parse Method
18485 Parser.parse = function(src, options, renderer) {
18486 var parser = new Parser(options, renderer);
18487 return parser.parse(src);
18494 Parser.prototype.parse = function(src) {
18495 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18496 this.tokens = src.reverse();
18499 while (this.next()) {
18510 Parser.prototype.next = function() {
18511 return this.token = this.tokens.pop();
18515 * Preview Next Token
18518 Parser.prototype.peek = function() {
18519 return this.tokens[this.tokens.length - 1] || 0;
18523 * Parse Text Tokens
18526 Parser.prototype.parseText = function() {
18527 var body = this.token.text;
18529 while (this.peek().type === 'text') {
18530 body += '\n' + this.next().text;
18533 return this.inline.output(body);
18537 * Parse Current Token
18540 Parser.prototype.tok = function() {
18541 switch (this.token.type) {
18546 return this.renderer.hr();
18549 return this.renderer.heading(
18550 this.inline.output(this.token.text),
18555 return this.renderer.code(this.token.text,
18557 this.token.escaped);
18570 for (i = 0; i < this.token.header.length; i++) {
18571 flags = { header: true, align: this.token.align[i] };
18572 cell += this.renderer.tablecell(
18573 this.inline.output(this.token.header[i]),
18574 { header: true, align: this.token.align[i] }
18577 header += this.renderer.tablerow(cell);
18579 for (i = 0; i < this.token.cells.length; i++) {
18580 row = this.token.cells[i];
18583 for (j = 0; j < row.length; j++) {
18584 cell += this.renderer.tablecell(
18585 this.inline.output(row[j]),
18586 { header: false, align: this.token.align[j] }
18590 body += this.renderer.tablerow(cell);
18592 return this.renderer.table(header, body);
18594 case 'blockquote_start': {
18597 while (this.next().type !== 'blockquote_end') {
18598 body += this.tok();
18601 return this.renderer.blockquote(body);
18603 case 'list_start': {
18605 , ordered = this.token.ordered;
18607 while (this.next().type !== 'list_end') {
18608 body += this.tok();
18611 return this.renderer.list(body, ordered);
18613 case 'list_item_start': {
18616 while (this.next().type !== 'list_item_end') {
18617 body += this.token.type === 'text'
18622 return this.renderer.listitem(body);
18624 case 'loose_item_start': {
18627 while (this.next().type !== 'list_item_end') {
18628 body += this.tok();
18631 return this.renderer.listitem(body);
18634 var html = !this.token.pre && !this.options.pedantic
18635 ? this.inline.output(this.token.text)
18637 return this.renderer.html(html);
18639 case 'paragraph': {
18640 return this.renderer.paragraph(this.inline.output(this.token.text));
18643 return this.renderer.paragraph(this.parseText());
18655 var marked = function (src, opt, callback) {
18656 if (callback || typeof opt === 'function') {
18662 opt = merge({}, marked.defaults, opt || {});
18664 var highlight = opt.highlight
18670 tokens = Lexer.lex(src, opt)
18672 return callback(e);
18675 pending = tokens.length;
18679 var done = function(err) {
18681 opt.highlight = highlight;
18682 return callback(err);
18688 out = Parser.parse(tokens, opt);
18693 opt.highlight = highlight;
18697 : callback(null, out);
18700 if (!highlight || highlight.length < 3) {
18704 delete opt.highlight;
18706 if (!pending) { return done(); }
18708 for (; i < tokens.length; i++) {
18710 if (token.type !== 'code') {
18711 return --pending || done();
18713 return highlight(token.text, token.lang, function(err, code) {
18714 if (err) { return done(err); }
18715 if (code == null || code === token.text) {
18716 return --pending || done();
18719 token.escaped = true;
18720 --pending || done();
18728 if (opt) { opt = merge({}, marked.defaults, opt); }
18729 return Parser.parse(Lexer.lex(src, opt), opt);
18731 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18732 if ((opt || marked.defaults).silent) {
18733 return '<p>An error occured:</p><pre>'
18734 + escape(e.message + '', true)
18746 marked.setOptions = function(opt) {
18747 merge(marked.defaults, opt);
18751 marked.defaults = {
18762 langPrefix: 'lang-',
18763 smartypants: false,
18765 renderer: new Renderer,
18773 marked.Parser = Parser;
18774 marked.parser = Parser.parse;
18776 marked.Renderer = Renderer;
18778 marked.Lexer = Lexer;
18779 marked.lexer = Lexer.lex;
18781 marked.InlineLexer = InlineLexer;
18782 marked.inlineLexer = InlineLexer.output;
18784 marked.parse = marked;
18786 Roo.Markdown.marked = marked;
18790 * Ext JS Library 1.1.1
18791 * Copyright(c) 2006-2007, Ext JS, LLC.
18793 * Originally Released Under LGPL - original licence link has changed is not relivant.
18796 * <script type="text/javascript">
18802 * These classes are derivatives of the similarly named classes in the YUI Library.
18803 * The original license:
18804 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18805 * Code licensed under the BSD License:
18806 * http://developer.yahoo.net/yui/license.txt
18811 var Event=Roo.EventManager;
18812 var Dom=Roo.lib.Dom;
18815 * @class Roo.dd.DragDrop
18816 * @extends Roo.util.Observable
18817 * Defines the interface and base operation of items that that can be
18818 * dragged or can be drop targets. It was designed to be extended, overriding
18819 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18820 * Up to three html elements can be associated with a DragDrop instance:
18822 * <li>linked element: the element that is passed into the constructor.
18823 * This is the element which defines the boundaries for interaction with
18824 * other DragDrop objects.</li>
18825 * <li>handle element(s): The drag operation only occurs if the element that
18826 * was clicked matches a handle element. By default this is the linked
18827 * element, but there are times that you will want only a portion of the
18828 * linked element to initiate the drag operation, and the setHandleElId()
18829 * method provides a way to define this.</li>
18830 * <li>drag element: this represents the element that would be moved along
18831 * with the cursor during a drag operation. By default, this is the linked
18832 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18833 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18836 * This class should not be instantiated until the onload event to ensure that
18837 * the associated elements are available.
18838 * The following would define a DragDrop obj that would interact with any
18839 * other DragDrop obj in the "group1" group:
18841 * dd = new Roo.dd.DragDrop("div1", "group1");
18843 * Since none of the event handlers have been implemented, nothing would
18844 * actually happen if you were to run the code above. Normally you would
18845 * override this class or one of the default implementations, but you can
18846 * also override the methods you want on an instance of the class...
18848 * dd.onDragDrop = function(e, id) {
18849 * alert("dd was dropped on " + id);
18853 * @param {String} id of the element that is linked to this instance
18854 * @param {String} sGroup the group of related DragDrop objects
18855 * @param {object} config an object containing configurable attributes
18856 * Valid properties for DragDrop:
18857 * padding, isTarget, maintainOffset, primaryButtonOnly
18859 Roo.dd.DragDrop = function(id, sGroup, config) {
18861 this.init(id, sGroup, config);
18866 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18869 * The id of the element associated with this object. This is what we
18870 * refer to as the "linked element" because the size and position of
18871 * this element is used to determine when the drag and drop objects have
18879 * Configuration attributes passed into the constructor
18886 * The id of the element that will be dragged. By default this is same
18887 * as the linked element , but could be changed to another element. Ex:
18889 * @property dragElId
18896 * the id of the element that initiates the drag operation. By default
18897 * this is the linked element, but could be changed to be a child of this
18898 * element. This lets us do things like only starting the drag when the
18899 * header element within the linked html element is clicked.
18900 * @property handleElId
18907 * An associative array of HTML tags that will be ignored if clicked.
18908 * @property invalidHandleTypes
18909 * @type {string: string}
18911 invalidHandleTypes: null,
18914 * An associative array of ids for elements that will be ignored if clicked
18915 * @property invalidHandleIds
18916 * @type {string: string}
18918 invalidHandleIds: null,
18921 * An indexted array of css class names for elements that will be ignored
18923 * @property invalidHandleClasses
18926 invalidHandleClasses: null,
18929 * The linked element's absolute X position at the time the drag was
18931 * @property startPageX
18938 * The linked element's absolute X position at the time the drag was
18940 * @property startPageY
18947 * The group defines a logical collection of DragDrop objects that are
18948 * related. Instances only get events when interacting with other
18949 * DragDrop object in the same group. This lets us define multiple
18950 * groups using a single DragDrop subclass if we want.
18952 * @type {string: string}
18957 * Individual drag/drop instances can be locked. This will prevent
18958 * onmousedown start drag.
18966 * Lock this instance
18969 lock: function() { this.locked = true; },
18972 * Unlock this instace
18975 unlock: function() { this.locked = false; },
18978 * By default, all insances can be a drop target. This can be disabled by
18979 * setting isTarget to false.
18986 * The padding configured for this drag and drop object for calculating
18987 * the drop zone intersection with this object.
18994 * Cached reference to the linked element
18995 * @property _domRef
19001 * Internal typeof flag
19002 * @property __ygDragDrop
19005 __ygDragDrop: true,
19008 * Set to true when horizontal contraints are applied
19009 * @property constrainX
19016 * Set to true when vertical contraints are applied
19017 * @property constrainY
19024 * The left constraint
19032 * The right constraint
19040 * The up constraint
19049 * The down constraint
19057 * Maintain offsets when we resetconstraints. Set to true when you want
19058 * the position of the element relative to its parent to stay the same
19059 * when the page changes
19061 * @property maintainOffset
19064 maintainOffset: false,
19067 * Array of pixel locations the element will snap to if we specified a
19068 * horizontal graduation/interval. This array is generated automatically
19069 * when you define a tick interval.
19076 * Array of pixel locations the element will snap to if we specified a
19077 * vertical graduation/interval. This array is generated automatically
19078 * when you define a tick interval.
19085 * By default the drag and drop instance will only respond to the primary
19086 * button click (left button for a right-handed mouse). Set to true to
19087 * allow drag and drop to start with any mouse click that is propogated
19089 * @property primaryButtonOnly
19092 primaryButtonOnly: true,
19095 * The availabe property is false until the linked dom element is accessible.
19096 * @property available
19102 * By default, drags can only be initiated if the mousedown occurs in the
19103 * region the linked element is. This is done in part to work around a
19104 * bug in some browsers that mis-report the mousedown if the previous
19105 * mouseup happened outside of the window. This property is set to true
19106 * if outer handles are defined.
19108 * @property hasOuterHandles
19112 hasOuterHandles: false,
19115 * Code that executes immediately before the startDrag event
19116 * @method b4StartDrag
19119 b4StartDrag: function(x, y) { },
19122 * Abstract method called after a drag/drop object is clicked
19123 * and the drag or mousedown time thresholds have beeen met.
19124 * @method startDrag
19125 * @param {int} X click location
19126 * @param {int} Y click location
19128 startDrag: function(x, y) { /* override this */ },
19131 * Code that executes immediately before the onDrag event
19135 b4Drag: function(e) { },
19138 * Abstract method called during the onMouseMove event while dragging an
19141 * @param {Event} e the mousemove event
19143 onDrag: function(e) { /* override this */ },
19146 * Abstract method called when this element fist begins hovering over
19147 * another DragDrop obj
19148 * @method onDragEnter
19149 * @param {Event} e the mousemove event
19150 * @param {String|DragDrop[]} id In POINT mode, the element
19151 * id this is hovering over. In INTERSECT mode, an array of one or more
19152 * dragdrop items being hovered over.
19154 onDragEnter: function(e, id) { /* override this */ },
19157 * Code that executes immediately before the onDragOver event
19158 * @method b4DragOver
19161 b4DragOver: function(e) { },
19164 * Abstract method called when this element is hovering over another
19166 * @method onDragOver
19167 * @param {Event} e the mousemove event
19168 * @param {String|DragDrop[]} id In POINT mode, the element
19169 * id this is hovering over. In INTERSECT mode, an array of dd items
19170 * being hovered over.
19172 onDragOver: function(e, id) { /* override this */ },
19175 * Code that executes immediately before the onDragOut event
19176 * @method b4DragOut
19179 b4DragOut: function(e) { },
19182 * Abstract method called when we are no longer hovering over an element
19183 * @method onDragOut
19184 * @param {Event} e the mousemove event
19185 * @param {String|DragDrop[]} id In POINT mode, the element
19186 * id this was hovering over. In INTERSECT mode, an array of dd items
19187 * that the mouse is no longer over.
19189 onDragOut: function(e, id) { /* override this */ },
19192 * Code that executes immediately before the onDragDrop event
19193 * @method b4DragDrop
19196 b4DragDrop: function(e) { },
19199 * Abstract method called when this item is dropped on another DragDrop
19201 * @method onDragDrop
19202 * @param {Event} e the mouseup event
19203 * @param {String|DragDrop[]} id In POINT mode, the element
19204 * id this was dropped on. In INTERSECT mode, an array of dd items this
19207 onDragDrop: function(e, id) { /* override this */ },
19210 * Abstract method called when this item is dropped on an area with no
19212 * @method onInvalidDrop
19213 * @param {Event} e the mouseup event
19215 onInvalidDrop: function(e) { /* override this */ },
19218 * Code that executes immediately before the endDrag event
19219 * @method b4EndDrag
19222 b4EndDrag: function(e) { },
19225 * Fired when we are done dragging the object
19227 * @param {Event} e the mouseup event
19229 endDrag: function(e) { /* override this */ },
19232 * Code executed immediately before the onMouseDown event
19233 * @method b4MouseDown
19234 * @param {Event} e the mousedown event
19237 b4MouseDown: function(e) { },
19240 * Event handler that fires when a drag/drop obj gets a mousedown
19241 * @method onMouseDown
19242 * @param {Event} e the mousedown event
19244 onMouseDown: function(e) { /* override this */ },
19247 * Event handler that fires when a drag/drop obj gets a mouseup
19248 * @method onMouseUp
19249 * @param {Event} e the mouseup event
19251 onMouseUp: function(e) { /* override this */ },
19254 * Override the onAvailable method to do what is needed after the initial
19255 * position was determined.
19256 * @method onAvailable
19258 onAvailable: function () {
19262 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19265 defaultPadding : {left:0, right:0, top:0, bottom:0},
19268 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19272 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19273 { dragElId: "existingProxyDiv" });
19274 dd.startDrag = function(){
19275 this.constrainTo("parent-id");
19278 * Or you can initalize it using the {@link Roo.Element} object:
19280 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19281 startDrag : function(){
19282 this.constrainTo("parent-id");
19286 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19287 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19288 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19289 * an object containing the sides to pad. For example: {right:10, bottom:10}
19290 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19292 constrainTo : function(constrainTo, pad, inContent){
19293 if(typeof pad == "number"){
19294 pad = {left: pad, right:pad, top:pad, bottom:pad};
19296 pad = pad || this.defaultPadding;
19297 var b = Roo.get(this.getEl()).getBox();
19298 var ce = Roo.get(constrainTo);
19299 var s = ce.getScroll();
19300 var c, cd = ce.dom;
19301 if(cd == document.body){
19302 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19305 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19309 var topSpace = b.y - c.y;
19310 var leftSpace = b.x - c.x;
19312 this.resetConstraints();
19313 this.setXConstraint(leftSpace - (pad.left||0), // left
19314 c.width - leftSpace - b.width - (pad.right||0) //right
19316 this.setYConstraint(topSpace - (pad.top||0), //top
19317 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19322 * Returns a reference to the linked element
19324 * @return {HTMLElement} the html element
19326 getEl: function() {
19327 if (!this._domRef) {
19328 this._domRef = Roo.getDom(this.id);
19331 return this._domRef;
19335 * Returns a reference to the actual element to drag. By default this is
19336 * the same as the html element, but it can be assigned to another
19337 * element. An example of this can be found in Roo.dd.DDProxy
19338 * @method getDragEl
19339 * @return {HTMLElement} the html element
19341 getDragEl: function() {
19342 return Roo.getDom(this.dragElId);
19346 * Sets up the DragDrop object. Must be called in the constructor of any
19347 * Roo.dd.DragDrop subclass
19349 * @param id the id of the linked element
19350 * @param {String} sGroup the group of related items
19351 * @param {object} config configuration attributes
19353 init: function(id, sGroup, config) {
19354 this.initTarget(id, sGroup, config);
19355 if (!Roo.isTouch) {
19356 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19358 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19359 // Event.on(this.id, "selectstart", Event.preventDefault);
19363 * Initializes Targeting functionality only... the object does not
19364 * get a mousedown handler.
19365 * @method initTarget
19366 * @param id the id of the linked element
19367 * @param {String} sGroup the group of related items
19368 * @param {object} config configuration attributes
19370 initTarget: function(id, sGroup, config) {
19372 // configuration attributes
19373 this.config = config || {};
19375 // create a local reference to the drag and drop manager
19376 this.DDM = Roo.dd.DDM;
19377 // initialize the groups array
19380 // assume that we have an element reference instead of an id if the
19381 // parameter is not a string
19382 if (typeof id !== "string") {
19389 // add to an interaction group
19390 this.addToGroup((sGroup) ? sGroup : "default");
19392 // We don't want to register this as the handle with the manager
19393 // so we just set the id rather than calling the setter.
19394 this.handleElId = id;
19396 // the linked element is the element that gets dragged by default
19397 this.setDragElId(id);
19399 // by default, clicked anchors will not start drag operations.
19400 this.invalidHandleTypes = { A: "A" };
19401 this.invalidHandleIds = {};
19402 this.invalidHandleClasses = [];
19404 this.applyConfig();
19406 this.handleOnAvailable();
19410 * Applies the configuration parameters that were passed into the constructor.
19411 * This is supposed to happen at each level through the inheritance chain. So
19412 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19413 * DragDrop in order to get all of the parameters that are available in
19415 * @method applyConfig
19417 applyConfig: function() {
19419 // configurable properties:
19420 // padding, isTarget, maintainOffset, primaryButtonOnly
19421 this.padding = this.config.padding || [0, 0, 0, 0];
19422 this.isTarget = (this.config.isTarget !== false);
19423 this.maintainOffset = (this.config.maintainOffset);
19424 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19429 * Executed when the linked element is available
19430 * @method handleOnAvailable
19433 handleOnAvailable: function() {
19434 this.available = true;
19435 this.resetConstraints();
19436 this.onAvailable();
19440 * Configures the padding for the target zone in px. Effectively expands
19441 * (or reduces) the virtual object size for targeting calculations.
19442 * Supports css-style shorthand; if only one parameter is passed, all sides
19443 * will have that padding, and if only two are passed, the top and bottom
19444 * will have the first param, the left and right the second.
19445 * @method setPadding
19446 * @param {int} iTop Top pad
19447 * @param {int} iRight Right pad
19448 * @param {int} iBot Bot pad
19449 * @param {int} iLeft Left pad
19451 setPadding: function(iTop, iRight, iBot, iLeft) {
19452 // this.padding = [iLeft, iRight, iTop, iBot];
19453 if (!iRight && 0 !== iRight) {
19454 this.padding = [iTop, iTop, iTop, iTop];
19455 } else if (!iBot && 0 !== iBot) {
19456 this.padding = [iTop, iRight, iTop, iRight];
19458 this.padding = [iTop, iRight, iBot, iLeft];
19463 * Stores the initial placement of the linked element.
19464 * @method setInitialPosition
19465 * @param {int} diffX the X offset, default 0
19466 * @param {int} diffY the Y offset, default 0
19468 setInitPosition: function(diffX, diffY) {
19469 var el = this.getEl();
19471 if (!this.DDM.verifyEl(el)) {
19475 var dx = diffX || 0;
19476 var dy = diffY || 0;
19478 var p = Dom.getXY( el );
19480 this.initPageX = p[0] - dx;
19481 this.initPageY = p[1] - dy;
19483 this.lastPageX = p[0];
19484 this.lastPageY = p[1];
19487 this.setStartPosition(p);
19491 * Sets the start position of the element. This is set when the obj
19492 * is initialized, the reset when a drag is started.
19493 * @method setStartPosition
19494 * @param pos current position (from previous lookup)
19497 setStartPosition: function(pos) {
19498 var p = pos || Dom.getXY( this.getEl() );
19499 this.deltaSetXY = null;
19501 this.startPageX = p[0];
19502 this.startPageY = p[1];
19506 * Add this instance to a group of related drag/drop objects. All
19507 * instances belong to at least one group, and can belong to as many
19508 * groups as needed.
19509 * @method addToGroup
19510 * @param sGroup {string} the name of the group
19512 addToGroup: function(sGroup) {
19513 this.groups[sGroup] = true;
19514 this.DDM.regDragDrop(this, sGroup);
19518 * Remove's this instance from the supplied interaction group
19519 * @method removeFromGroup
19520 * @param {string} sGroup The group to drop
19522 removeFromGroup: function(sGroup) {
19523 if (this.groups[sGroup]) {
19524 delete this.groups[sGroup];
19527 this.DDM.removeDDFromGroup(this, sGroup);
19531 * Allows you to specify that an element other than the linked element
19532 * will be moved with the cursor during a drag
19533 * @method setDragElId
19534 * @param id {string} the id of the element that will be used to initiate the drag
19536 setDragElId: function(id) {
19537 this.dragElId = id;
19541 * Allows you to specify a child of the linked element that should be
19542 * used to initiate the drag operation. An example of this would be if
19543 * you have a content div with text and links. Clicking anywhere in the
19544 * content area would normally start the drag operation. Use this method
19545 * to specify that an element inside of the content div is the element
19546 * that starts the drag operation.
19547 * @method setHandleElId
19548 * @param id {string} the id of the element that will be used to
19549 * initiate the drag.
19551 setHandleElId: function(id) {
19552 if (typeof id !== "string") {
19555 this.handleElId = id;
19556 this.DDM.regHandle(this.id, id);
19560 * Allows you to set an element outside of the linked element as a drag
19562 * @method setOuterHandleElId
19563 * @param id the id of the element that will be used to initiate the drag
19565 setOuterHandleElId: function(id) {
19566 if (typeof id !== "string") {
19569 Event.on(id, "mousedown",
19570 this.handleMouseDown, this);
19571 this.setHandleElId(id);
19573 this.hasOuterHandles = true;
19577 * Remove all drag and drop hooks for this element
19580 unreg: function() {
19581 Event.un(this.id, "mousedown",
19582 this.handleMouseDown);
19583 Event.un(this.id, "touchstart",
19584 this.handleMouseDown);
19585 this._domRef = null;
19586 this.DDM._remove(this);
19589 destroy : function(){
19594 * Returns true if this instance is locked, or the drag drop mgr is locked
19595 * (meaning that all drag/drop is disabled on the page.)
19597 * @return {boolean} true if this obj or all drag/drop is locked, else
19600 isLocked: function() {
19601 return (this.DDM.isLocked() || this.locked);
19605 * Fired when this object is clicked
19606 * @method handleMouseDown
19608 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19611 handleMouseDown: function(e, oDD){
19613 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19614 //Roo.log('not touch/ button !=0');
19617 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19618 return; // double touch..
19622 if (this.isLocked()) {
19623 //Roo.log('locked');
19627 this.DDM.refreshCache(this.groups);
19628 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19629 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19630 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19631 //Roo.log('no outer handes or not over target');
19634 // Roo.log('check validator');
19635 if (this.clickValidator(e)) {
19636 // Roo.log('validate success');
19637 // set the initial element position
19638 this.setStartPosition();
19641 this.b4MouseDown(e);
19642 this.onMouseDown(e);
19644 this.DDM.handleMouseDown(e, this);
19646 this.DDM.stopEvent(e);
19654 clickValidator: function(e) {
19655 var target = e.getTarget();
19656 return ( this.isValidHandleChild(target) &&
19657 (this.id == this.handleElId ||
19658 this.DDM.handleWasClicked(target, this.id)) );
19662 * Allows you to specify a tag name that should not start a drag operation
19663 * when clicked. This is designed to facilitate embedding links within a
19664 * drag handle that do something other than start the drag.
19665 * @method addInvalidHandleType
19666 * @param {string} tagName the type of element to exclude
19668 addInvalidHandleType: function(tagName) {
19669 var type = tagName.toUpperCase();
19670 this.invalidHandleTypes[type] = type;
19674 * Lets you to specify an element id for a child of a drag handle
19675 * that should not initiate a drag
19676 * @method addInvalidHandleId
19677 * @param {string} id the element id of the element you wish to ignore
19679 addInvalidHandleId: function(id) {
19680 if (typeof id !== "string") {
19683 this.invalidHandleIds[id] = id;
19687 * Lets you specify a css class of elements that will not initiate a drag
19688 * @method addInvalidHandleClass
19689 * @param {string} cssClass the class of the elements you wish to ignore
19691 addInvalidHandleClass: function(cssClass) {
19692 this.invalidHandleClasses.push(cssClass);
19696 * Unsets an excluded tag name set by addInvalidHandleType
19697 * @method removeInvalidHandleType
19698 * @param {string} tagName the type of element to unexclude
19700 removeInvalidHandleType: function(tagName) {
19701 var type = tagName.toUpperCase();
19702 // this.invalidHandleTypes[type] = null;
19703 delete this.invalidHandleTypes[type];
19707 * Unsets an invalid handle id
19708 * @method removeInvalidHandleId
19709 * @param {string} id the id of the element to re-enable
19711 removeInvalidHandleId: function(id) {
19712 if (typeof id !== "string") {
19715 delete this.invalidHandleIds[id];
19719 * Unsets an invalid css class
19720 * @method removeInvalidHandleClass
19721 * @param {string} cssClass the class of the element(s) you wish to
19724 removeInvalidHandleClass: function(cssClass) {
19725 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19726 if (this.invalidHandleClasses[i] == cssClass) {
19727 delete this.invalidHandleClasses[i];
19733 * Checks the tag exclusion list to see if this click should be ignored
19734 * @method isValidHandleChild
19735 * @param {HTMLElement} node the HTMLElement to evaluate
19736 * @return {boolean} true if this is a valid tag type, false if not
19738 isValidHandleChild: function(node) {
19741 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19744 nodeName = node.nodeName.toUpperCase();
19746 nodeName = node.nodeName;
19748 valid = valid && !this.invalidHandleTypes[nodeName];
19749 valid = valid && !this.invalidHandleIds[node.id];
19751 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19752 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19761 * Create the array of horizontal tick marks if an interval was specified
19762 * in setXConstraint().
19763 * @method setXTicks
19766 setXTicks: function(iStartX, iTickSize) {
19768 this.xTickSize = iTickSize;
19772 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19774 this.xTicks[this.xTicks.length] = i;
19779 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19781 this.xTicks[this.xTicks.length] = i;
19786 this.xTicks.sort(this.DDM.numericSort) ;
19790 * Create the array of vertical tick marks if an interval was specified in
19791 * setYConstraint().
19792 * @method setYTicks
19795 setYTicks: function(iStartY, iTickSize) {
19797 this.yTickSize = iTickSize;
19801 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19803 this.yTicks[this.yTicks.length] = i;
19808 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19810 this.yTicks[this.yTicks.length] = i;
19815 this.yTicks.sort(this.DDM.numericSort) ;
19819 * By default, the element can be dragged any place on the screen. Use
19820 * this method to limit the horizontal travel of the element. Pass in
19821 * 0,0 for the parameters if you want to lock the drag to the y axis.
19822 * @method setXConstraint
19823 * @param {int} iLeft the number of pixels the element can move to the left
19824 * @param {int} iRight the number of pixels the element can move to the
19826 * @param {int} iTickSize optional parameter for specifying that the
19828 * should move iTickSize pixels at a time.
19830 setXConstraint: function(iLeft, iRight, iTickSize) {
19831 this.leftConstraint = iLeft;
19832 this.rightConstraint = iRight;
19834 this.minX = this.initPageX - iLeft;
19835 this.maxX = this.initPageX + iRight;
19836 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19838 this.constrainX = true;
19842 * Clears any constraints applied to this instance. Also clears ticks
19843 * since they can't exist independent of a constraint at this time.
19844 * @method clearConstraints
19846 clearConstraints: function() {
19847 this.constrainX = false;
19848 this.constrainY = false;
19853 * Clears any tick interval defined for this instance
19854 * @method clearTicks
19856 clearTicks: function() {
19857 this.xTicks = null;
19858 this.yTicks = null;
19859 this.xTickSize = 0;
19860 this.yTickSize = 0;
19864 * By default, the element can be dragged any place on the screen. Set
19865 * this to limit the vertical travel of the element. Pass in 0,0 for the
19866 * parameters if you want to lock the drag to the x axis.
19867 * @method setYConstraint
19868 * @param {int} iUp the number of pixels the element can move up
19869 * @param {int} iDown the number of pixels the element can move down
19870 * @param {int} iTickSize optional parameter for specifying that the
19871 * element should move iTickSize pixels at a time.
19873 setYConstraint: function(iUp, iDown, iTickSize) {
19874 this.topConstraint = iUp;
19875 this.bottomConstraint = iDown;
19877 this.minY = this.initPageY - iUp;
19878 this.maxY = this.initPageY + iDown;
19879 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19881 this.constrainY = true;
19886 * resetConstraints must be called if you manually reposition a dd element.
19887 * @method resetConstraints
19888 * @param {boolean} maintainOffset
19890 resetConstraints: function() {
19893 // Maintain offsets if necessary
19894 if (this.initPageX || this.initPageX === 0) {
19895 // figure out how much this thing has moved
19896 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19897 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19899 this.setInitPosition(dx, dy);
19901 // This is the first time we have detected the element's position
19903 this.setInitPosition();
19906 if (this.constrainX) {
19907 this.setXConstraint( this.leftConstraint,
19908 this.rightConstraint,
19912 if (this.constrainY) {
19913 this.setYConstraint( this.topConstraint,
19914 this.bottomConstraint,
19920 * Normally the drag element is moved pixel by pixel, but we can specify
19921 * that it move a number of pixels at a time. This method resolves the
19922 * location when we have it set up like this.
19924 * @param {int} val where we want to place the object
19925 * @param {int[]} tickArray sorted array of valid points
19926 * @return {int} the closest tick
19929 getTick: function(val, tickArray) {
19932 // If tick interval is not defined, it is effectively 1 pixel,
19933 // so we return the value passed to us.
19935 } else if (tickArray[0] >= val) {
19936 // The value is lower than the first tick, so we return the first
19938 return tickArray[0];
19940 for (var i=0, len=tickArray.length; i<len; ++i) {
19942 if (tickArray[next] && tickArray[next] >= val) {
19943 var diff1 = val - tickArray[i];
19944 var diff2 = tickArray[next] - val;
19945 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19949 // The value is larger than the last tick, so we return the last
19951 return tickArray[tickArray.length - 1];
19958 * @return {string} string representation of the dd obj
19960 toString: function() {
19961 return ("DragDrop " + this.id);
19969 * Ext JS Library 1.1.1
19970 * Copyright(c) 2006-2007, Ext JS, LLC.
19972 * Originally Released Under LGPL - original licence link has changed is not relivant.
19975 * <script type="text/javascript">
19980 * The drag and drop utility provides a framework for building drag and drop
19981 * applications. In addition to enabling drag and drop for specific elements,
19982 * the drag and drop elements are tracked by the manager class, and the
19983 * interactions between the various elements are tracked during the drag and
19984 * the implementing code is notified about these important moments.
19987 // Only load the library once. Rewriting the manager class would orphan
19988 // existing drag and drop instances.
19989 if (!Roo.dd.DragDropMgr) {
19992 * @class Roo.dd.DragDropMgr
19993 * DragDropMgr is a singleton that tracks the element interaction for
19994 * all DragDrop items in the window. Generally, you will not call
19995 * this class directly, but it does have helper methods that could
19996 * be useful in your DragDrop implementations.
19999 Roo.dd.DragDropMgr = function() {
20001 var Event = Roo.EventManager;
20006 * Two dimensional Array of registered DragDrop objects. The first
20007 * dimension is the DragDrop item group, the second the DragDrop
20010 * @type {string: string}
20017 * Array of element ids defined as drag handles. Used to determine
20018 * if the element that generated the mousedown event is actually the
20019 * handle and not the html element itself.
20020 * @property handleIds
20021 * @type {string: string}
20028 * the DragDrop object that is currently being dragged
20029 * @property dragCurrent
20037 * the DragDrop object(s) that are being hovered over
20038 * @property dragOvers
20046 * the X distance between the cursor and the object being dragged
20055 * the Y distance between the cursor and the object being dragged
20064 * Flag to determine if we should prevent the default behavior of the
20065 * events we define. By default this is true, but this can be set to
20066 * false if you need the default behavior (not recommended)
20067 * @property preventDefault
20071 preventDefault: true,
20074 * Flag to determine if we should stop the propagation of the events
20075 * we generate. This is true by default but you may want to set it to
20076 * false if the html element contains other features that require the
20078 * @property stopPropagation
20082 stopPropagation: true,
20085 * Internal flag that is set to true when drag and drop has been
20087 * @property initialized
20094 * All drag and drop can be disabled.
20102 * Called the first time an element is registered.
20108 this.initialized = true;
20112 * In point mode, drag and drop interaction is defined by the
20113 * location of the cursor during the drag/drop
20121 * In intersect mode, drag and drop interactio nis defined by the
20122 * overlap of two or more drag and drop objects.
20123 * @property INTERSECT
20130 * The current drag and drop mode. Default: POINT
20138 * Runs method on all drag and drop objects
20139 * @method _execOnAll
20143 _execOnAll: function(sMethod, args) {
20144 for (var i in this.ids) {
20145 for (var j in this.ids[i]) {
20146 var oDD = this.ids[i][j];
20147 if (! this.isTypeOfDD(oDD)) {
20150 oDD[sMethod].apply(oDD, args);
20156 * Drag and drop initialization. Sets up the global event handlers
20161 _onLoad: function() {
20165 if (!Roo.isTouch) {
20166 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20167 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20169 Event.on(document, "touchend", this.handleMouseUp, this, true);
20170 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20172 Event.on(window, "unload", this._onUnload, this, true);
20173 Event.on(window, "resize", this._onResize, this, true);
20174 // Event.on(window, "mouseout", this._test);
20179 * Reset constraints on all drag and drop objs
20180 * @method _onResize
20184 _onResize: function(e) {
20185 this._execOnAll("resetConstraints", []);
20189 * Lock all drag and drop functionality
20193 lock: function() { this.locked = true; },
20196 * Unlock all drag and drop functionality
20200 unlock: function() { this.locked = false; },
20203 * Is drag and drop locked?
20205 * @return {boolean} True if drag and drop is locked, false otherwise.
20208 isLocked: function() { return this.locked; },
20211 * Location cache that is set for all drag drop objects when a drag is
20212 * initiated, cleared when the drag is finished.
20213 * @property locationCache
20220 * Set useCache to false if you want to force object the lookup of each
20221 * drag and drop linked element constantly during a drag.
20222 * @property useCache
20229 * The number of pixels that the mouse needs to move after the
20230 * mousedown before the drag is initiated. Default=3;
20231 * @property clickPixelThresh
20235 clickPixelThresh: 3,
20238 * The number of milliseconds after the mousedown event to initiate the
20239 * drag if we don't get a mouseup event. Default=1000
20240 * @property clickTimeThresh
20244 clickTimeThresh: 350,
20247 * Flag that indicates that either the drag pixel threshold or the
20248 * mousdown time threshold has been met
20249 * @property dragThreshMet
20254 dragThreshMet: false,
20257 * Timeout used for the click time threshold
20258 * @property clickTimeout
20263 clickTimeout: null,
20266 * The X position of the mousedown event stored for later use when a
20267 * drag threshold is met.
20276 * The Y position of the mousedown event stored for later use when a
20277 * drag threshold is met.
20286 * Each DragDrop instance must be registered with the DragDropMgr.
20287 * This is executed in DragDrop.init()
20288 * @method regDragDrop
20289 * @param {DragDrop} oDD the DragDrop object to register
20290 * @param {String} sGroup the name of the group this element belongs to
20293 regDragDrop: function(oDD, sGroup) {
20294 if (!this.initialized) { this.init(); }
20296 if (!this.ids[sGroup]) {
20297 this.ids[sGroup] = {};
20299 this.ids[sGroup][oDD.id] = oDD;
20303 * Removes the supplied dd instance from the supplied group. Executed
20304 * by DragDrop.removeFromGroup, so don't call this function directly.
20305 * @method removeDDFromGroup
20309 removeDDFromGroup: function(oDD, sGroup) {
20310 if (!this.ids[sGroup]) {
20311 this.ids[sGroup] = {};
20314 var obj = this.ids[sGroup];
20315 if (obj && obj[oDD.id]) {
20316 delete obj[oDD.id];
20321 * Unregisters a drag and drop item. This is executed in
20322 * DragDrop.unreg, use that method instead of calling this directly.
20327 _remove: function(oDD) {
20328 for (var g in oDD.groups) {
20329 if (g && this.ids[g][oDD.id]) {
20330 delete this.ids[g][oDD.id];
20333 delete this.handleIds[oDD.id];
20337 * Each DragDrop handle element must be registered. This is done
20338 * automatically when executing DragDrop.setHandleElId()
20339 * @method regHandle
20340 * @param {String} sDDId the DragDrop id this element is a handle for
20341 * @param {String} sHandleId the id of the element that is the drag
20345 regHandle: function(sDDId, sHandleId) {
20346 if (!this.handleIds[sDDId]) {
20347 this.handleIds[sDDId] = {};
20349 this.handleIds[sDDId][sHandleId] = sHandleId;
20353 * Utility function to determine if a given element has been
20354 * registered as a drag drop item.
20355 * @method isDragDrop
20356 * @param {String} id the element id to check
20357 * @return {boolean} true if this element is a DragDrop item,
20361 isDragDrop: function(id) {
20362 return ( this.getDDById(id) ) ? true : false;
20366 * Returns the drag and drop instances that are in all groups the
20367 * passed in instance belongs to.
20368 * @method getRelated
20369 * @param {DragDrop} p_oDD the obj to get related data for
20370 * @param {boolean} bTargetsOnly if true, only return targetable objs
20371 * @return {DragDrop[]} the related instances
20374 getRelated: function(p_oDD, bTargetsOnly) {
20376 for (var i in p_oDD.groups) {
20377 for (j in this.ids[i]) {
20378 var dd = this.ids[i][j];
20379 if (! this.isTypeOfDD(dd)) {
20382 if (!bTargetsOnly || dd.isTarget) {
20383 oDDs[oDDs.length] = dd;
20392 * Returns true if the specified dd target is a legal target for
20393 * the specifice drag obj
20394 * @method isLegalTarget
20395 * @param {DragDrop} the drag obj
20396 * @param {DragDrop} the target
20397 * @return {boolean} true if the target is a legal target for the
20401 isLegalTarget: function (oDD, oTargetDD) {
20402 var targets = this.getRelated(oDD, true);
20403 for (var i=0, len=targets.length;i<len;++i) {
20404 if (targets[i].id == oTargetDD.id) {
20413 * My goal is to be able to transparently determine if an object is
20414 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20415 * returns "object", oDD.constructor.toString() always returns
20416 * "DragDrop" and not the name of the subclass. So for now it just
20417 * evaluates a well-known variable in DragDrop.
20418 * @method isTypeOfDD
20419 * @param {Object} the object to evaluate
20420 * @return {boolean} true if typeof oDD = DragDrop
20423 isTypeOfDD: function (oDD) {
20424 return (oDD && oDD.__ygDragDrop);
20428 * Utility function to determine if a given element has been
20429 * registered as a drag drop handle for the given Drag Drop object.
20431 * @param {String} id the element id to check
20432 * @return {boolean} true if this element is a DragDrop handle, false
20436 isHandle: function(sDDId, sHandleId) {
20437 return ( this.handleIds[sDDId] &&
20438 this.handleIds[sDDId][sHandleId] );
20442 * Returns the DragDrop instance for a given id
20443 * @method getDDById
20444 * @param {String} id the id of the DragDrop object
20445 * @return {DragDrop} the drag drop object, null if it is not found
20448 getDDById: function(id) {
20449 for (var i in this.ids) {
20450 if (this.ids[i][id]) {
20451 return this.ids[i][id];
20458 * Fired after a registered DragDrop object gets the mousedown event.
20459 * Sets up the events required to track the object being dragged
20460 * @method handleMouseDown
20461 * @param {Event} e the event
20462 * @param oDD the DragDrop object being dragged
20466 handleMouseDown: function(e, oDD) {
20468 Roo.QuickTips.disable();
20470 this.currentTarget = e.getTarget();
20472 this.dragCurrent = oDD;
20474 var el = oDD.getEl();
20476 // track start position
20477 this.startX = e.getPageX();
20478 this.startY = e.getPageY();
20480 this.deltaX = this.startX - el.offsetLeft;
20481 this.deltaY = this.startY - el.offsetTop;
20483 this.dragThreshMet = false;
20485 this.clickTimeout = setTimeout(
20487 var DDM = Roo.dd.DDM;
20488 DDM.startDrag(DDM.startX, DDM.startY);
20490 this.clickTimeThresh );
20494 * Fired when either the drag pixel threshol or the mousedown hold
20495 * time threshold has been met.
20496 * @method startDrag
20497 * @param x {int} the X position of the original mousedown
20498 * @param y {int} the Y position of the original mousedown
20501 startDrag: function(x, y) {
20502 clearTimeout(this.clickTimeout);
20503 if (this.dragCurrent) {
20504 this.dragCurrent.b4StartDrag(x, y);
20505 this.dragCurrent.startDrag(x, y);
20507 this.dragThreshMet = true;
20511 * Internal function to handle the mouseup event. Will be invoked
20512 * from the context of the document.
20513 * @method handleMouseUp
20514 * @param {Event} e the event
20518 handleMouseUp: function(e) {
20521 Roo.QuickTips.enable();
20523 if (! this.dragCurrent) {
20527 clearTimeout(this.clickTimeout);
20529 if (this.dragThreshMet) {
20530 this.fireEvents(e, true);
20540 * Utility to stop event propagation and event default, if these
20541 * features are turned on.
20542 * @method stopEvent
20543 * @param {Event} e the event as returned by this.getEvent()
20546 stopEvent: function(e){
20547 if(this.stopPropagation) {
20548 e.stopPropagation();
20551 if (this.preventDefault) {
20552 e.preventDefault();
20557 * Internal function to clean up event handlers after the drag
20558 * operation is complete
20560 * @param {Event} e the event
20564 stopDrag: function(e) {
20565 // Fire the drag end event for the item that was dragged
20566 if (this.dragCurrent) {
20567 if (this.dragThreshMet) {
20568 this.dragCurrent.b4EndDrag(e);
20569 this.dragCurrent.endDrag(e);
20572 this.dragCurrent.onMouseUp(e);
20575 this.dragCurrent = null;
20576 this.dragOvers = {};
20580 * Internal function to handle the mousemove event. Will be invoked
20581 * from the context of the html element.
20583 * @TODO figure out what we can do about mouse events lost when the
20584 * user drags objects beyond the window boundary. Currently we can
20585 * detect this in internet explorer by verifying that the mouse is
20586 * down during the mousemove event. Firefox doesn't give us the
20587 * button state on the mousemove event.
20588 * @method handleMouseMove
20589 * @param {Event} e the event
20593 handleMouseMove: function(e) {
20594 if (! this.dragCurrent) {
20598 // var button = e.which || e.button;
20600 // check for IE mouseup outside of page boundary
20601 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20603 return this.handleMouseUp(e);
20606 if (!this.dragThreshMet) {
20607 var diffX = Math.abs(this.startX - e.getPageX());
20608 var diffY = Math.abs(this.startY - e.getPageY());
20609 if (diffX > this.clickPixelThresh ||
20610 diffY > this.clickPixelThresh) {
20611 this.startDrag(this.startX, this.startY);
20615 if (this.dragThreshMet) {
20616 this.dragCurrent.b4Drag(e);
20617 this.dragCurrent.onDrag(e);
20618 if(!this.dragCurrent.moveOnly){
20619 this.fireEvents(e, false);
20629 * Iterates over all of the DragDrop elements to find ones we are
20630 * hovering over or dropping on
20631 * @method fireEvents
20632 * @param {Event} e the event
20633 * @param {boolean} isDrop is this a drop op or a mouseover op?
20637 fireEvents: function(e, isDrop) {
20638 var dc = this.dragCurrent;
20640 // If the user did the mouse up outside of the window, we could
20641 // get here even though we have ended the drag.
20642 if (!dc || dc.isLocked()) {
20646 var pt = e.getPoint();
20648 // cache the previous dragOver array
20654 var enterEvts = [];
20656 // Check to see if the object(s) we were hovering over is no longer
20657 // being hovered over so we can fire the onDragOut event
20658 for (var i in this.dragOvers) {
20660 var ddo = this.dragOvers[i];
20662 if (! this.isTypeOfDD(ddo)) {
20666 if (! this.isOverTarget(pt, ddo, this.mode)) {
20667 outEvts.push( ddo );
20670 oldOvers[i] = true;
20671 delete this.dragOvers[i];
20674 for (var sGroup in dc.groups) {
20676 if ("string" != typeof sGroup) {
20680 for (i in this.ids[sGroup]) {
20681 var oDD = this.ids[sGroup][i];
20682 if (! this.isTypeOfDD(oDD)) {
20686 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20687 if (this.isOverTarget(pt, oDD, this.mode)) {
20688 // look for drop interactions
20690 dropEvts.push( oDD );
20691 // look for drag enter and drag over interactions
20694 // initial drag over: dragEnter fires
20695 if (!oldOvers[oDD.id]) {
20696 enterEvts.push( oDD );
20697 // subsequent drag overs: dragOver fires
20699 overEvts.push( oDD );
20702 this.dragOvers[oDD.id] = oDD;
20710 if (outEvts.length) {
20711 dc.b4DragOut(e, outEvts);
20712 dc.onDragOut(e, outEvts);
20715 if (enterEvts.length) {
20716 dc.onDragEnter(e, enterEvts);
20719 if (overEvts.length) {
20720 dc.b4DragOver(e, overEvts);
20721 dc.onDragOver(e, overEvts);
20724 if (dropEvts.length) {
20725 dc.b4DragDrop(e, dropEvts);
20726 dc.onDragDrop(e, dropEvts);
20730 // fire dragout events
20732 for (i=0, len=outEvts.length; i<len; ++i) {
20733 dc.b4DragOut(e, outEvts[i].id);
20734 dc.onDragOut(e, outEvts[i].id);
20737 // fire enter events
20738 for (i=0,len=enterEvts.length; i<len; ++i) {
20739 // dc.b4DragEnter(e, oDD.id);
20740 dc.onDragEnter(e, enterEvts[i].id);
20743 // fire over events
20744 for (i=0,len=overEvts.length; i<len; ++i) {
20745 dc.b4DragOver(e, overEvts[i].id);
20746 dc.onDragOver(e, overEvts[i].id);
20749 // fire drop events
20750 for (i=0, len=dropEvts.length; i<len; ++i) {
20751 dc.b4DragDrop(e, dropEvts[i].id);
20752 dc.onDragDrop(e, dropEvts[i].id);
20757 // notify about a drop that did not find a target
20758 if (isDrop && !dropEvts.length) {
20759 dc.onInvalidDrop(e);
20765 * Helper function for getting the best match from the list of drag
20766 * and drop objects returned by the drag and drop events when we are
20767 * in INTERSECT mode. It returns either the first object that the
20768 * cursor is over, or the object that has the greatest overlap with
20769 * the dragged element.
20770 * @method getBestMatch
20771 * @param {DragDrop[]} dds The array of drag and drop objects
20773 * @return {DragDrop} The best single match
20776 getBestMatch: function(dds) {
20778 // Return null if the input is not what we expect
20779 //if (!dds || !dds.length || dds.length == 0) {
20781 // If there is only one item, it wins
20782 //} else if (dds.length == 1) {
20784 var len = dds.length;
20789 // Loop through the targeted items
20790 for (var i=0; i<len; ++i) {
20792 // If the cursor is over the object, it wins. If the
20793 // cursor is over multiple matches, the first one we come
20795 if (dd.cursorIsOver) {
20798 // Otherwise the object with the most overlap wins
20801 winner.overlap.getArea() < dd.overlap.getArea()) {
20812 * Refreshes the cache of the top-left and bottom-right points of the
20813 * drag and drop objects in the specified group(s). This is in the
20814 * format that is stored in the drag and drop instance, so typical
20817 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20821 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20823 * @TODO this really should be an indexed array. Alternatively this
20824 * method could accept both.
20825 * @method refreshCache
20826 * @param {Object} groups an associative array of groups to refresh
20829 refreshCache: function(groups) {
20830 for (var sGroup in groups) {
20831 if ("string" != typeof sGroup) {
20834 for (var i in this.ids[sGroup]) {
20835 var oDD = this.ids[sGroup][i];
20837 if (this.isTypeOfDD(oDD)) {
20838 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20839 var loc = this.getLocation(oDD);
20841 this.locationCache[oDD.id] = loc;
20843 delete this.locationCache[oDD.id];
20844 // this will unregister the drag and drop object if
20845 // the element is not in a usable state
20854 * This checks to make sure an element exists and is in the DOM. The
20855 * main purpose is to handle cases where innerHTML is used to remove
20856 * drag and drop objects from the DOM. IE provides an 'unspecified
20857 * error' when trying to access the offsetParent of such an element
20859 * @param {HTMLElement} el the element to check
20860 * @return {boolean} true if the element looks usable
20863 verifyEl: function(el) {
20868 parent = el.offsetParent;
20871 parent = el.offsetParent;
20882 * Returns a Region object containing the drag and drop element's position
20883 * and size, including the padding configured for it
20884 * @method getLocation
20885 * @param {DragDrop} oDD the drag and drop object to get the
20887 * @return {Roo.lib.Region} a Region object representing the total area
20888 * the element occupies, including any padding
20889 * the instance is configured for.
20892 getLocation: function(oDD) {
20893 if (! this.isTypeOfDD(oDD)) {
20897 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20900 pos= Roo.lib.Dom.getXY(el);
20908 x2 = x1 + el.offsetWidth;
20910 y2 = y1 + el.offsetHeight;
20912 t = y1 - oDD.padding[0];
20913 r = x2 + oDD.padding[1];
20914 b = y2 + oDD.padding[2];
20915 l = x1 - oDD.padding[3];
20917 return new Roo.lib.Region( t, r, b, l );
20921 * Checks the cursor location to see if it over the target
20922 * @method isOverTarget
20923 * @param {Roo.lib.Point} pt The point to evaluate
20924 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20925 * @return {boolean} true if the mouse is over the target
20929 isOverTarget: function(pt, oTarget, intersect) {
20930 // use cache if available
20931 var loc = this.locationCache[oTarget.id];
20932 if (!loc || !this.useCache) {
20933 loc = this.getLocation(oTarget);
20934 this.locationCache[oTarget.id] = loc;
20942 oTarget.cursorIsOver = loc.contains( pt );
20944 // DragDrop is using this as a sanity check for the initial mousedown
20945 // in this case we are done. In POINT mode, if the drag obj has no
20946 // contraints, we are also done. Otherwise we need to evaluate the
20947 // location of the target as related to the actual location of the
20948 // dragged element.
20949 var dc = this.dragCurrent;
20950 if (!dc || !dc.getTargetCoord ||
20951 (!intersect && !dc.constrainX && !dc.constrainY)) {
20952 return oTarget.cursorIsOver;
20955 oTarget.overlap = null;
20957 // Get the current location of the drag element, this is the
20958 // location of the mouse event less the delta that represents
20959 // where the original mousedown happened on the element. We
20960 // need to consider constraints and ticks as well.
20961 var pos = dc.getTargetCoord(pt.x, pt.y);
20963 var el = dc.getDragEl();
20964 var curRegion = new Roo.lib.Region( pos.y,
20965 pos.x + el.offsetWidth,
20966 pos.y + el.offsetHeight,
20969 var overlap = curRegion.intersect(loc);
20972 oTarget.overlap = overlap;
20973 return (intersect) ? true : oTarget.cursorIsOver;
20980 * unload event handler
20981 * @method _onUnload
20985 _onUnload: function(e, me) {
20986 Roo.dd.DragDropMgr.unregAll();
20990 * Cleans up the drag and drop events and objects.
20995 unregAll: function() {
20997 if (this.dragCurrent) {
20999 this.dragCurrent = null;
21002 this._execOnAll("unreg", []);
21004 for (i in this.elementCache) {
21005 delete this.elementCache[i];
21008 this.elementCache = {};
21013 * A cache of DOM elements
21014 * @property elementCache
21021 * Get the wrapper for the DOM element specified
21022 * @method getElWrapper
21023 * @param {String} id the id of the element to get
21024 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21026 * @deprecated This wrapper isn't that useful
21029 getElWrapper: function(id) {
21030 var oWrapper = this.elementCache[id];
21031 if (!oWrapper || !oWrapper.el) {
21032 oWrapper = this.elementCache[id] =
21033 new this.ElementWrapper(Roo.getDom(id));
21039 * Returns the actual DOM element
21040 * @method getElement
21041 * @param {String} id the id of the elment to get
21042 * @return {Object} The element
21043 * @deprecated use Roo.getDom instead
21046 getElement: function(id) {
21047 return Roo.getDom(id);
21051 * Returns the style property for the DOM element (i.e.,
21052 * document.getElById(id).style)
21054 * @param {String} id the id of the elment to get
21055 * @return {Object} The style property of the element
21056 * @deprecated use Roo.getDom instead
21059 getCss: function(id) {
21060 var el = Roo.getDom(id);
21061 return (el) ? el.style : null;
21065 * Inner class for cached elements
21066 * @class DragDropMgr.ElementWrapper
21071 ElementWrapper: function(el) {
21076 this.el = el || null;
21081 this.id = this.el && el.id;
21083 * A reference to the style property
21086 this.css = this.el && el.style;
21090 * Returns the X position of an html element
21092 * @param el the element for which to get the position
21093 * @return {int} the X coordinate
21095 * @deprecated use Roo.lib.Dom.getX instead
21098 getPosX: function(el) {
21099 return Roo.lib.Dom.getX(el);
21103 * Returns the Y position of an html element
21105 * @param el the element for which to get the position
21106 * @return {int} the Y coordinate
21107 * @deprecated use Roo.lib.Dom.getY instead
21110 getPosY: function(el) {
21111 return Roo.lib.Dom.getY(el);
21115 * Swap two nodes. In IE, we use the native method, for others we
21116 * emulate the IE behavior
21118 * @param n1 the first node to swap
21119 * @param n2 the other node to swap
21122 swapNode: function(n1, n2) {
21126 var p = n2.parentNode;
21127 var s = n2.nextSibling;
21130 p.insertBefore(n1, n2);
21131 } else if (n2 == n1.nextSibling) {
21132 p.insertBefore(n2, n1);
21134 n1.parentNode.replaceChild(n2, n1);
21135 p.insertBefore(n1, s);
21141 * Returns the current scroll position
21142 * @method getScroll
21146 getScroll: function () {
21147 var t, l, dde=document.documentElement, db=document.body;
21148 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21150 l = dde.scrollLeft;
21157 return { top: t, left: l };
21161 * Returns the specified element style property
21163 * @param {HTMLElement} el the element
21164 * @param {string} styleProp the style property
21165 * @return {string} The value of the style property
21166 * @deprecated use Roo.lib.Dom.getStyle
21169 getStyle: function(el, styleProp) {
21170 return Roo.fly(el).getStyle(styleProp);
21174 * Gets the scrollTop
21175 * @method getScrollTop
21176 * @return {int} the document's scrollTop
21179 getScrollTop: function () { return this.getScroll().top; },
21182 * Gets the scrollLeft
21183 * @method getScrollLeft
21184 * @return {int} the document's scrollTop
21187 getScrollLeft: function () { return this.getScroll().left; },
21190 * Sets the x/y position of an element to the location of the
21193 * @param {HTMLElement} moveEl The element to move
21194 * @param {HTMLElement} targetEl The position reference element
21197 moveToEl: function (moveEl, targetEl) {
21198 var aCoord = Roo.lib.Dom.getXY(targetEl);
21199 Roo.lib.Dom.setXY(moveEl, aCoord);
21203 * Numeric array sort function
21204 * @method numericSort
21207 numericSort: function(a, b) { return (a - b); },
21211 * @property _timeoutCount
21218 * Trying to make the load order less important. Without this we get
21219 * an error if this file is loaded before the Event Utility.
21220 * @method _addListeners
21224 _addListeners: function() {
21225 var DDM = Roo.dd.DDM;
21226 if ( Roo.lib.Event && document ) {
21229 if (DDM._timeoutCount > 2000) {
21231 setTimeout(DDM._addListeners, 10);
21232 if (document && document.body) {
21233 DDM._timeoutCount += 1;
21240 * Recursively searches the immediate parent and all child nodes for
21241 * the handle element in order to determine wheter or not it was
21243 * @method handleWasClicked
21244 * @param node the html element to inspect
21247 handleWasClicked: function(node, id) {
21248 if (this.isHandle(id, node.id)) {
21251 // check to see if this is a text node child of the one we want
21252 var p = node.parentNode;
21255 if (this.isHandle(id, p.id)) {
21270 // shorter alias, save a few bytes
21271 Roo.dd.DDM = Roo.dd.DragDropMgr;
21272 Roo.dd.DDM._addListeners();
21276 * Ext JS Library 1.1.1
21277 * Copyright(c) 2006-2007, Ext JS, LLC.
21279 * Originally Released Under LGPL - original licence link has changed is not relivant.
21282 * <script type="text/javascript">
21287 * A DragDrop implementation where the linked element follows the
21288 * mouse cursor during a drag.
21289 * @extends Roo.dd.DragDrop
21291 * @param {String} id the id of the linked element
21292 * @param {String} sGroup the group of related DragDrop items
21293 * @param {object} config an object containing configurable attributes
21294 * Valid properties for DD:
21297 Roo.dd.DD = function(id, sGroup, config) {
21299 this.init(id, sGroup, config);
21303 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21306 * When set to true, the utility automatically tries to scroll the browser
21307 * window wehn a drag and drop element is dragged near the viewport boundary.
21308 * Defaults to true.
21315 * Sets the pointer offset to the distance between the linked element's top
21316 * left corner and the location the element was clicked
21317 * @method autoOffset
21318 * @param {int} iPageX the X coordinate of the click
21319 * @param {int} iPageY the Y coordinate of the click
21321 autoOffset: function(iPageX, iPageY) {
21322 var x = iPageX - this.startPageX;
21323 var y = iPageY - this.startPageY;
21324 this.setDelta(x, y);
21328 * Sets the pointer offset. You can call this directly to force the
21329 * offset to be in a particular location (e.g., pass in 0,0 to set it
21330 * to the center of the object)
21332 * @param {int} iDeltaX the distance from the left
21333 * @param {int} iDeltaY the distance from the top
21335 setDelta: function(iDeltaX, iDeltaY) {
21336 this.deltaX = iDeltaX;
21337 this.deltaY = iDeltaY;
21341 * Sets the drag element to the location of the mousedown or click event,
21342 * maintaining the cursor location relative to the location on the element
21343 * that was clicked. Override this if you want to place the element in a
21344 * location other than where the cursor is.
21345 * @method setDragElPos
21346 * @param {int} iPageX the X coordinate of the mousedown or drag event
21347 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21349 setDragElPos: function(iPageX, iPageY) {
21350 // the first time we do this, we are going to check to make sure
21351 // the element has css positioning
21353 var el = this.getDragEl();
21354 this.alignElWithMouse(el, iPageX, iPageY);
21358 * Sets the element to the location of the mousedown or click event,
21359 * maintaining the cursor location relative to the location on the element
21360 * that was clicked. Override this if you want to place the element in a
21361 * location other than where the cursor is.
21362 * @method alignElWithMouse
21363 * @param {HTMLElement} el the element to move
21364 * @param {int} iPageX the X coordinate of the mousedown or drag event
21365 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21367 alignElWithMouse: function(el, iPageX, iPageY) {
21368 var oCoord = this.getTargetCoord(iPageX, iPageY);
21369 var fly = el.dom ? el : Roo.fly(el);
21370 if (!this.deltaSetXY) {
21371 var aCoord = [oCoord.x, oCoord.y];
21373 var newLeft = fly.getLeft(true);
21374 var newTop = fly.getTop(true);
21375 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21377 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21380 this.cachePosition(oCoord.x, oCoord.y);
21381 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21386 * Saves the most recent position so that we can reset the constraints and
21387 * tick marks on-demand. We need to know this so that we can calculate the
21388 * number of pixels the element is offset from its original position.
21389 * @method cachePosition
21390 * @param iPageX the current x position (optional, this just makes it so we
21391 * don't have to look it up again)
21392 * @param iPageY the current y position (optional, this just makes it so we
21393 * don't have to look it up again)
21395 cachePosition: function(iPageX, iPageY) {
21397 this.lastPageX = iPageX;
21398 this.lastPageY = iPageY;
21400 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21401 this.lastPageX = aCoord[0];
21402 this.lastPageY = aCoord[1];
21407 * Auto-scroll the window if the dragged object has been moved beyond the
21408 * visible window boundary.
21409 * @method autoScroll
21410 * @param {int} x the drag element's x position
21411 * @param {int} y the drag element's y position
21412 * @param {int} h the height of the drag element
21413 * @param {int} w the width of the drag element
21416 autoScroll: function(x, y, h, w) {
21419 // The client height
21420 var clientH = Roo.lib.Dom.getViewWidth();
21422 // The client width
21423 var clientW = Roo.lib.Dom.getViewHeight();
21425 // The amt scrolled down
21426 var st = this.DDM.getScrollTop();
21428 // The amt scrolled right
21429 var sl = this.DDM.getScrollLeft();
21431 // Location of the bottom of the element
21434 // Location of the right of the element
21437 // The distance from the cursor to the bottom of the visible area,
21438 // adjusted so that we don't scroll if the cursor is beyond the
21439 // element drag constraints
21440 var toBot = (clientH + st - y - this.deltaY);
21442 // The distance from the cursor to the right of the visible area
21443 var toRight = (clientW + sl - x - this.deltaX);
21446 // How close to the edge the cursor must be before we scroll
21447 // var thresh = (document.all) ? 100 : 40;
21450 // How many pixels to scroll per autoscroll op. This helps to reduce
21451 // clunky scrolling. IE is more sensitive about this ... it needs this
21452 // value to be higher.
21453 var scrAmt = (document.all) ? 80 : 30;
21455 // Scroll down if we are near the bottom of the visible page and the
21456 // obj extends below the crease
21457 if ( bot > clientH && toBot < thresh ) {
21458 window.scrollTo(sl, st + scrAmt);
21461 // Scroll up if the window is scrolled down and the top of the object
21462 // goes above the top border
21463 if ( y < st && st > 0 && y - st < thresh ) {
21464 window.scrollTo(sl, st - scrAmt);
21467 // Scroll right if the obj is beyond the right border and the cursor is
21468 // near the border.
21469 if ( right > clientW && toRight < thresh ) {
21470 window.scrollTo(sl + scrAmt, st);
21473 // Scroll left if the window has been scrolled to the right and the obj
21474 // extends past the left border
21475 if ( x < sl && sl > 0 && x - sl < thresh ) {
21476 window.scrollTo(sl - scrAmt, st);
21482 * Finds the location the element should be placed if we want to move
21483 * it to where the mouse location less the click offset would place us.
21484 * @method getTargetCoord
21485 * @param {int} iPageX the X coordinate of the click
21486 * @param {int} iPageY the Y coordinate of the click
21487 * @return an object that contains the coordinates (Object.x and Object.y)
21490 getTargetCoord: function(iPageX, iPageY) {
21493 var x = iPageX - this.deltaX;
21494 var y = iPageY - this.deltaY;
21496 if (this.constrainX) {
21497 if (x < this.minX) { x = this.minX; }
21498 if (x > this.maxX) { x = this.maxX; }
21501 if (this.constrainY) {
21502 if (y < this.minY) { y = this.minY; }
21503 if (y > this.maxY) { y = this.maxY; }
21506 x = this.getTick(x, this.xTicks);
21507 y = this.getTick(y, this.yTicks);
21514 * Sets up config options specific to this class. Overrides
21515 * Roo.dd.DragDrop, but all versions of this method through the
21516 * inheritance chain are called
21518 applyConfig: function() {
21519 Roo.dd.DD.superclass.applyConfig.call(this);
21520 this.scroll = (this.config.scroll !== false);
21524 * Event that fires prior to the onMouseDown event. Overrides
21527 b4MouseDown: function(e) {
21528 // this.resetConstraints();
21529 this.autoOffset(e.getPageX(),
21534 * Event that fires prior to the onDrag event. Overrides
21537 b4Drag: function(e) {
21538 this.setDragElPos(e.getPageX(),
21542 toString: function() {
21543 return ("DD " + this.id);
21546 //////////////////////////////////////////////////////////////////////////
21547 // Debugging ygDragDrop events that can be overridden
21548 //////////////////////////////////////////////////////////////////////////
21550 startDrag: function(x, y) {
21553 onDrag: function(e) {
21556 onDragEnter: function(e, id) {
21559 onDragOver: function(e, id) {
21562 onDragOut: function(e, id) {
21565 onDragDrop: function(e, id) {
21568 endDrag: function(e) {
21575 * Ext JS Library 1.1.1
21576 * Copyright(c) 2006-2007, Ext JS, LLC.
21578 * Originally Released Under LGPL - original licence link has changed is not relivant.
21581 * <script type="text/javascript">
21585 * @class Roo.dd.DDProxy
21586 * A DragDrop implementation that inserts an empty, bordered div into
21587 * the document that follows the cursor during drag operations. At the time of
21588 * the click, the frame div is resized to the dimensions of the linked html
21589 * element, and moved to the exact location of the linked element.
21591 * References to the "frame" element refer to the single proxy element that
21592 * was created to be dragged in place of all DDProxy elements on the
21595 * @extends Roo.dd.DD
21597 * @param {String} id the id of the linked html element
21598 * @param {String} sGroup the group of related DragDrop objects
21599 * @param {object} config an object containing configurable attributes
21600 * Valid properties for DDProxy in addition to those in DragDrop:
21601 * resizeFrame, centerFrame, dragElId
21603 Roo.dd.DDProxy = function(id, sGroup, config) {
21605 this.init(id, sGroup, config);
21611 * The default drag frame div id
21612 * @property Roo.dd.DDProxy.dragElId
21616 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21618 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21621 * By default we resize the drag frame to be the same size as the element
21622 * we want to drag (this is to get the frame effect). We can turn it off
21623 * if we want a different behavior.
21624 * @property resizeFrame
21630 * By default the frame is positioned exactly where the drag element is, so
21631 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21632 * you do not have constraints on the obj is to have the drag frame centered
21633 * around the cursor. Set centerFrame to true for this effect.
21634 * @property centerFrame
21637 centerFrame: false,
21640 * Creates the proxy element if it does not yet exist
21641 * @method createFrame
21643 createFrame: function() {
21645 var body = document.body;
21647 if (!body || !body.firstChild) {
21648 setTimeout( function() { self.createFrame(); }, 50 );
21652 var div = this.getDragEl();
21655 div = document.createElement("div");
21656 div.id = this.dragElId;
21659 s.position = "absolute";
21660 s.visibility = "hidden";
21662 s.border = "2px solid #aaa";
21665 // appendChild can blow up IE if invoked prior to the window load event
21666 // while rendering a table. It is possible there are other scenarios
21667 // that would cause this to happen as well.
21668 body.insertBefore(div, body.firstChild);
21673 * Initialization for the drag frame element. Must be called in the
21674 * constructor of all subclasses
21675 * @method initFrame
21677 initFrame: function() {
21678 this.createFrame();
21681 applyConfig: function() {
21682 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21684 this.resizeFrame = (this.config.resizeFrame !== false);
21685 this.centerFrame = (this.config.centerFrame);
21686 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21690 * Resizes the drag frame to the dimensions of the clicked object, positions
21691 * it over the object, and finally displays it
21692 * @method showFrame
21693 * @param {int} iPageX X click position
21694 * @param {int} iPageY Y click position
21697 showFrame: function(iPageX, iPageY) {
21698 var el = this.getEl();
21699 var dragEl = this.getDragEl();
21700 var s = dragEl.style;
21702 this._resizeProxy();
21704 if (this.centerFrame) {
21705 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21706 Math.round(parseInt(s.height, 10)/2) );
21709 this.setDragElPos(iPageX, iPageY);
21711 Roo.fly(dragEl).show();
21715 * The proxy is automatically resized to the dimensions of the linked
21716 * element when a drag is initiated, unless resizeFrame is set to false
21717 * @method _resizeProxy
21720 _resizeProxy: function() {
21721 if (this.resizeFrame) {
21722 var el = this.getEl();
21723 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21727 // overrides Roo.dd.DragDrop
21728 b4MouseDown: function(e) {
21729 var x = e.getPageX();
21730 var y = e.getPageY();
21731 this.autoOffset(x, y);
21732 this.setDragElPos(x, y);
21735 // overrides Roo.dd.DragDrop
21736 b4StartDrag: function(x, y) {
21737 // show the drag frame
21738 this.showFrame(x, y);
21741 // overrides Roo.dd.DragDrop
21742 b4EndDrag: function(e) {
21743 Roo.fly(this.getDragEl()).hide();
21746 // overrides Roo.dd.DragDrop
21747 // By default we try to move the element to the last location of the frame.
21748 // This is so that the default behavior mirrors that of Roo.dd.DD.
21749 endDrag: function(e) {
21751 var lel = this.getEl();
21752 var del = this.getDragEl();
21754 // Show the drag frame briefly so we can get its position
21755 del.style.visibility = "";
21758 // Hide the linked element before the move to get around a Safari
21760 lel.style.visibility = "hidden";
21761 Roo.dd.DDM.moveToEl(lel, del);
21762 del.style.visibility = "hidden";
21763 lel.style.visibility = "";
21768 beforeMove : function(){
21772 afterDrag : function(){
21776 toString: function() {
21777 return ("DDProxy " + this.id);
21783 * Ext JS Library 1.1.1
21784 * Copyright(c) 2006-2007, Ext JS, LLC.
21786 * Originally Released Under LGPL - original licence link has changed is not relivant.
21789 * <script type="text/javascript">
21793 * @class Roo.dd.DDTarget
21794 * A DragDrop implementation that does not move, but can be a drop
21795 * target. You would get the same result by simply omitting implementation
21796 * for the event callbacks, but this way we reduce the processing cost of the
21797 * event listener and the callbacks.
21798 * @extends Roo.dd.DragDrop
21800 * @param {String} id the id of the element that is a drop target
21801 * @param {String} sGroup the group of related DragDrop objects
21802 * @param {object} config an object containing configurable attributes
21803 * Valid properties for DDTarget in addition to those in
21807 Roo.dd.DDTarget = function(id, sGroup, config) {
21809 this.initTarget(id, sGroup, config);
21811 if (config && (config.listeners || config.events)) {
21812 Roo.dd.DragDrop.superclass.constructor.call(this, {
21813 listeners : config.listeners || {},
21814 events : config.events || {}
21819 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21820 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21821 toString: function() {
21822 return ("DDTarget " + this.id);
21827 * Ext JS Library 1.1.1
21828 * Copyright(c) 2006-2007, Ext JS, LLC.
21830 * Originally Released Under LGPL - original licence link has changed is not relivant.
21833 * <script type="text/javascript">
21838 * @class Roo.dd.ScrollManager
21839 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21840 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21843 Roo.dd.ScrollManager = function(){
21844 var ddm = Roo.dd.DragDropMgr;
21851 var onStop = function(e){
21856 var triggerRefresh = function(){
21857 if(ddm.dragCurrent){
21858 ddm.refreshCache(ddm.dragCurrent.groups);
21862 var doScroll = function(){
21863 if(ddm.dragCurrent){
21864 var dds = Roo.dd.ScrollManager;
21866 if(proc.el.scroll(proc.dir, dds.increment)){
21870 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21875 var clearProc = function(){
21877 clearInterval(proc.id);
21884 var startProc = function(el, dir){
21885 Roo.log('scroll startproc');
21889 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21892 var onFire = function(e, isDrop){
21894 if(isDrop || !ddm.dragCurrent){ return; }
21895 var dds = Roo.dd.ScrollManager;
21896 if(!dragEl || dragEl != ddm.dragCurrent){
21897 dragEl = ddm.dragCurrent;
21898 // refresh regions on drag start
21899 dds.refreshCache();
21902 var xy = Roo.lib.Event.getXY(e);
21903 var pt = new Roo.lib.Point(xy[0], xy[1]);
21904 for(var id in els){
21905 var el = els[id], r = el._region;
21906 if(r && r.contains(pt) && el.isScrollable()){
21907 if(r.bottom - pt.y <= dds.thresh){
21909 startProc(el, "down");
21912 }else if(r.right - pt.x <= dds.thresh){
21914 startProc(el, "left");
21917 }else if(pt.y - r.top <= dds.thresh){
21919 startProc(el, "up");
21922 }else if(pt.x - r.left <= dds.thresh){
21924 startProc(el, "right");
21933 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21934 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21938 * Registers new overflow element(s) to auto scroll
21939 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21941 register : function(el){
21942 if(el instanceof Array){
21943 for(var i = 0, len = el.length; i < len; i++) {
21944 this.register(el[i]);
21950 Roo.dd.ScrollManager.els = els;
21954 * Unregisters overflow element(s) so they are no longer scrolled
21955 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21957 unregister : function(el){
21958 if(el instanceof Array){
21959 for(var i = 0, len = el.length; i < len; i++) {
21960 this.unregister(el[i]);
21969 * The number of pixels from the edge of a container the pointer needs to be to
21970 * trigger scrolling (defaults to 25)
21976 * The number of pixels to scroll in each scroll increment (defaults to 50)
21982 * The frequency of scrolls in milliseconds (defaults to 500)
21988 * True to animate the scroll (defaults to true)
21994 * The animation duration in seconds -
21995 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22001 * Manually trigger a cache refresh.
22003 refreshCache : function(){
22004 for(var id in els){
22005 if(typeof els[id] == 'object'){ // for people extending the object prototype
22006 els[id]._region = els[id].getRegion();
22013 * Ext JS Library 1.1.1
22014 * Copyright(c) 2006-2007, Ext JS, LLC.
22016 * Originally Released Under LGPL - original licence link has changed is not relivant.
22019 * <script type="text/javascript">
22024 * @class Roo.dd.Registry
22025 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
22026 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22029 Roo.dd.Registry = function(){
22032 var autoIdSeed = 0;
22034 var getId = function(el, autogen){
22035 if(typeof el == "string"){
22039 if(!id && autogen !== false){
22040 id = "roodd-" + (++autoIdSeed);
22048 * Register a drag drop element
22049 * @param {String|HTMLElement} element The id or DOM node to register
22050 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22051 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
22052 * knows how to interpret, plus there are some specific properties known to the Registry that should be
22053 * populated in the data object (if applicable):
22055 Value Description<br />
22056 --------- ------------------------------------------<br />
22057 handles Array of DOM nodes that trigger dragging<br />
22058 for the element being registered<br />
22059 isHandle True if the element passed in triggers<br />
22060 dragging itself, else false
22063 register : function(el, data){
22065 if(typeof el == "string"){
22066 el = document.getElementById(el);
22069 elements[getId(el)] = data;
22070 if(data.isHandle !== false){
22071 handles[data.ddel.id] = data;
22074 var hs = data.handles;
22075 for(var i = 0, len = hs.length; i < len; i++){
22076 handles[getId(hs[i])] = data;
22082 * Unregister a drag drop element
22083 * @param {String|HTMLElement} element The id or DOM node to unregister
22085 unregister : function(el){
22086 var id = getId(el, false);
22087 var data = elements[id];
22089 delete elements[id];
22091 var hs = data.handles;
22092 for(var i = 0, len = hs.length; i < len; i++){
22093 delete handles[getId(hs[i], false)];
22100 * Returns the handle registered for a DOM Node by id
22101 * @param {String|HTMLElement} id The DOM node or id to look up
22102 * @return {Object} handle The custom handle data
22104 getHandle : function(id){
22105 if(typeof id != "string"){ // must be element?
22108 return handles[id];
22112 * Returns the handle that is registered for the DOM node that is the target of the event
22113 * @param {Event} e The event
22114 * @return {Object} handle The custom handle data
22116 getHandleFromEvent : function(e){
22117 var t = Roo.lib.Event.getTarget(e);
22118 return t ? handles[t.id] : null;
22122 * Returns a custom data object that is registered for a DOM node by id
22123 * @param {String|HTMLElement} id The DOM node or id to look up
22124 * @return {Object} data The custom data
22126 getTarget : function(id){
22127 if(typeof id != "string"){ // must be element?
22130 return elements[id];
22134 * Returns a custom data object that is registered for the DOM node that is the target of the event
22135 * @param {Event} e The event
22136 * @return {Object} data The custom data
22138 getTargetFromEvent : function(e){
22139 var t = Roo.lib.Event.getTarget(e);
22140 return t ? elements[t.id] || handles[t.id] : null;
22145 * Ext JS Library 1.1.1
22146 * Copyright(c) 2006-2007, Ext JS, LLC.
22148 * Originally Released Under LGPL - original licence link has changed is not relivant.
22151 * <script type="text/javascript">
22156 * @class Roo.dd.StatusProxy
22157 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22158 * default drag proxy used by all Roo.dd components.
22160 * @param {Object} config
22162 Roo.dd.StatusProxy = function(config){
22163 Roo.apply(this, config);
22164 this.id = this.id || Roo.id();
22165 this.el = new Roo.Layer({
22167 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22168 {tag: "div", cls: "x-dd-drop-icon"},
22169 {tag: "div", cls: "x-dd-drag-ghost"}
22172 shadow: !config || config.shadow !== false
22174 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22175 this.dropStatus = this.dropNotAllowed;
22178 Roo.dd.StatusProxy.prototype = {
22180 * @cfg {String} dropAllowed
22181 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22183 dropAllowed : "x-dd-drop-ok",
22185 * @cfg {String} dropNotAllowed
22186 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22188 dropNotAllowed : "x-dd-drop-nodrop",
22191 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22192 * over the current target element.
22193 * @param {String} cssClass The css class for the new drop status indicator image
22195 setStatus : function(cssClass){
22196 cssClass = cssClass || this.dropNotAllowed;
22197 if(this.dropStatus != cssClass){
22198 this.el.replaceClass(this.dropStatus, cssClass);
22199 this.dropStatus = cssClass;
22204 * Resets the status indicator to the default dropNotAllowed value
22205 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22207 reset : function(clearGhost){
22208 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22209 this.dropStatus = this.dropNotAllowed;
22211 this.ghost.update("");
22216 * Updates the contents of the ghost element
22217 * @param {String} html The html that will replace the current innerHTML of the ghost element
22219 update : function(html){
22220 if(typeof html == "string"){
22221 this.ghost.update(html);
22223 this.ghost.update("");
22224 html.style.margin = "0";
22225 this.ghost.dom.appendChild(html);
22227 // ensure float = none set?? cant remember why though.
22228 var el = this.ghost.dom.firstChild;
22230 Roo.fly(el).setStyle('float', 'none');
22235 * Returns the underlying proxy {@link Roo.Layer}
22236 * @return {Roo.Layer} el
22238 getEl : function(){
22243 * Returns the ghost element
22244 * @return {Roo.Element} el
22246 getGhost : function(){
22252 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22254 hide : function(clear){
22262 * Stops the repair animation if it's currently running
22265 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22271 * Displays this proxy
22278 * Force the Layer to sync its shadow and shim positions to the element
22285 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22286 * invalid drop operation by the item being dragged.
22287 * @param {Array} xy The XY position of the element ([x, y])
22288 * @param {Function} callback The function to call after the repair is complete
22289 * @param {Object} scope The scope in which to execute the callback
22291 repair : function(xy, callback, scope){
22292 this.callback = callback;
22293 this.scope = scope;
22294 if(xy && this.animRepair !== false){
22295 this.el.addClass("x-dd-drag-repair");
22296 this.el.hideUnders(true);
22297 this.anim = this.el.shift({
22298 duration: this.repairDuration || .5,
22302 callback: this.afterRepair,
22306 this.afterRepair();
22311 afterRepair : function(){
22313 if(typeof this.callback == "function"){
22314 this.callback.call(this.scope || this);
22316 this.callback = null;
22321 * Ext JS Library 1.1.1
22322 * Copyright(c) 2006-2007, Ext JS, LLC.
22324 * Originally Released Under LGPL - original licence link has changed is not relivant.
22327 * <script type="text/javascript">
22331 * @class Roo.dd.DragSource
22332 * @extends Roo.dd.DDProxy
22333 * A simple class that provides the basic implementation needed to make any element draggable.
22335 * @param {String/HTMLElement/Element} el The container element
22336 * @param {Object} config
22338 Roo.dd.DragSource = function(el, config){
22339 this.el = Roo.get(el);
22340 this.dragData = {};
22342 Roo.apply(this, config);
22345 this.proxy = new Roo.dd.StatusProxy();
22348 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22349 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22351 this.dragging = false;
22354 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22356 * @cfg {String} dropAllowed
22357 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22359 dropAllowed : "x-dd-drop-ok",
22361 * @cfg {String} dropNotAllowed
22362 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22364 dropNotAllowed : "x-dd-drop-nodrop",
22367 * Returns the data object associated with this drag source
22368 * @return {Object} data An object containing arbitrary data
22370 getDragData : function(e){
22371 return this.dragData;
22375 onDragEnter : function(e, id){
22376 var target = Roo.dd.DragDropMgr.getDDById(id);
22377 this.cachedTarget = target;
22378 if(this.beforeDragEnter(target, e, id) !== false){
22379 if(target.isNotifyTarget){
22380 var status = target.notifyEnter(this, e, this.dragData);
22381 this.proxy.setStatus(status);
22383 this.proxy.setStatus(this.dropAllowed);
22386 if(this.afterDragEnter){
22388 * An empty function by default, but provided so that you can perform a custom action
22389 * when the dragged item enters the drop target by providing an implementation.
22390 * @param {Roo.dd.DragDrop} target The drop target
22391 * @param {Event} e The event object
22392 * @param {String} id The id of the dragged element
22393 * @method afterDragEnter
22395 this.afterDragEnter(target, e, id);
22401 * An empty function by default, but provided so that you can perform a custom action
22402 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22403 * @param {Roo.dd.DragDrop} target The drop target
22404 * @param {Event} e The event object
22405 * @param {String} id The id of the dragged element
22406 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22408 beforeDragEnter : function(target, e, id){
22413 alignElWithMouse: function() {
22414 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22419 onDragOver : function(e, id){
22420 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22421 if(this.beforeDragOver(target, e, id) !== false){
22422 if(target.isNotifyTarget){
22423 var status = target.notifyOver(this, e, this.dragData);
22424 this.proxy.setStatus(status);
22427 if(this.afterDragOver){
22429 * An empty function by default, but provided so that you can perform a custom action
22430 * while the dragged item is over the drop target by providing an implementation.
22431 * @param {Roo.dd.DragDrop} target The drop target
22432 * @param {Event} e The event object
22433 * @param {String} id The id of the dragged element
22434 * @method afterDragOver
22436 this.afterDragOver(target, e, id);
22442 * An empty function by default, but provided so that you can perform a custom action
22443 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22444 * @param {Roo.dd.DragDrop} target The drop target
22445 * @param {Event} e The event object
22446 * @param {String} id The id of the dragged element
22447 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22449 beforeDragOver : function(target, e, id){
22454 onDragOut : function(e, id){
22455 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22456 if(this.beforeDragOut(target, e, id) !== false){
22457 if(target.isNotifyTarget){
22458 target.notifyOut(this, e, this.dragData);
22460 this.proxy.reset();
22461 if(this.afterDragOut){
22463 * An empty function by default, but provided so that you can perform a custom action
22464 * after the dragged item is dragged out of the target without dropping.
22465 * @param {Roo.dd.DragDrop} target The drop target
22466 * @param {Event} e The event object
22467 * @param {String} id The id of the dragged element
22468 * @method afterDragOut
22470 this.afterDragOut(target, e, id);
22473 this.cachedTarget = null;
22477 * An empty function by default, but provided so that you can perform a custom action before the dragged
22478 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22479 * @param {Roo.dd.DragDrop} target The drop target
22480 * @param {Event} e The event object
22481 * @param {String} id The id of the dragged element
22482 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22484 beforeDragOut : function(target, e, id){
22489 onDragDrop : function(e, id){
22490 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22491 if(this.beforeDragDrop(target, e, id) !== false){
22492 if(target.isNotifyTarget){
22493 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22494 this.onValidDrop(target, e, id);
22496 this.onInvalidDrop(target, e, id);
22499 this.onValidDrop(target, e, id);
22502 if(this.afterDragDrop){
22504 * An empty function by default, but provided so that you can perform a custom action
22505 * after a valid drag drop has occurred by providing an implementation.
22506 * @param {Roo.dd.DragDrop} target The drop target
22507 * @param {Event} e The event object
22508 * @param {String} id The id of the dropped element
22509 * @method afterDragDrop
22511 this.afterDragDrop(target, e, id);
22514 delete this.cachedTarget;
22518 * An empty function by default, but provided so that you can perform a custom action before the dragged
22519 * item is dropped onto the target and optionally cancel the onDragDrop.
22520 * @param {Roo.dd.DragDrop} target The drop target
22521 * @param {Event} e The event object
22522 * @param {String} id The id of the dragged element
22523 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22525 beforeDragDrop : function(target, e, id){
22530 onValidDrop : function(target, e, id){
22532 if(this.afterValidDrop){
22534 * An empty function by default, but provided so that you can perform a custom action
22535 * after a valid drop has occurred by providing an implementation.
22536 * @param {Object} target The target DD
22537 * @param {Event} e The event object
22538 * @param {String} id The id of the dropped element
22539 * @method afterInvalidDrop
22541 this.afterValidDrop(target, e, id);
22546 getRepairXY : function(e, data){
22547 return this.el.getXY();
22551 onInvalidDrop : function(target, e, id){
22552 this.beforeInvalidDrop(target, e, id);
22553 if(this.cachedTarget){
22554 if(this.cachedTarget.isNotifyTarget){
22555 this.cachedTarget.notifyOut(this, e, this.dragData);
22557 this.cacheTarget = null;
22559 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22561 if(this.afterInvalidDrop){
22563 * An empty function by default, but provided so that you can perform a custom action
22564 * after an invalid drop has occurred by providing an implementation.
22565 * @param {Event} e The event object
22566 * @param {String} id The id of the dropped element
22567 * @method afterInvalidDrop
22569 this.afterInvalidDrop(e, id);
22574 afterRepair : function(){
22576 this.el.highlight(this.hlColor || "c3daf9");
22578 this.dragging = false;
22582 * An empty function by default, but provided so that you can perform a custom action after an invalid
22583 * drop has occurred.
22584 * @param {Roo.dd.DragDrop} target The drop target
22585 * @param {Event} e The event object
22586 * @param {String} id The id of the dragged element
22587 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22589 beforeInvalidDrop : function(target, e, id){
22594 handleMouseDown : function(e){
22595 if(this.dragging) {
22598 var data = this.getDragData(e);
22599 if(data && this.onBeforeDrag(data, e) !== false){
22600 this.dragData = data;
22602 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22607 * An empty function by default, but provided so that you can perform a custom action before the initial
22608 * drag event begins and optionally cancel it.
22609 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22610 * @param {Event} e The event object
22611 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22613 onBeforeDrag : function(data, e){
22618 * An empty function by default, but provided so that you can perform a custom action once the initial
22619 * drag event has begun. The drag cannot be canceled from this function.
22620 * @param {Number} x The x position of the click on the dragged object
22621 * @param {Number} y The y position of the click on the dragged object
22623 onStartDrag : Roo.emptyFn,
22625 // private - YUI override
22626 startDrag : function(x, y){
22627 this.proxy.reset();
22628 this.dragging = true;
22629 this.proxy.update("");
22630 this.onInitDrag(x, y);
22635 onInitDrag : function(x, y){
22636 var clone = this.el.dom.cloneNode(true);
22637 clone.id = Roo.id(); // prevent duplicate ids
22638 this.proxy.update(clone);
22639 this.onStartDrag(x, y);
22644 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22645 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22647 getProxy : function(){
22652 * Hides the drag source's {@link Roo.dd.StatusProxy}
22654 hideProxy : function(){
22656 this.proxy.reset(true);
22657 this.dragging = false;
22661 triggerCacheRefresh : function(){
22662 Roo.dd.DDM.refreshCache(this.groups);
22665 // private - override to prevent hiding
22666 b4EndDrag: function(e) {
22669 // private - override to prevent moving
22670 endDrag : function(e){
22671 this.onEndDrag(this.dragData, e);
22675 onEndDrag : function(data, e){
22678 // private - pin to cursor
22679 autoOffset : function(x, y) {
22680 this.setDelta(-12, -20);
22684 * Ext JS Library 1.1.1
22685 * Copyright(c) 2006-2007, Ext JS, LLC.
22687 * Originally Released Under LGPL - original licence link has changed is not relivant.
22690 * <script type="text/javascript">
22695 * @class Roo.dd.DropTarget
22696 * @extends Roo.dd.DDTarget
22697 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22698 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22700 * @param {String/HTMLElement/Element} el The container element
22701 * @param {Object} config
22703 Roo.dd.DropTarget = function(el, config){
22704 this.el = Roo.get(el);
22706 var listeners = false; ;
22707 if (config && config.listeners) {
22708 listeners= config.listeners;
22709 delete config.listeners;
22711 Roo.apply(this, config);
22713 if(this.containerScroll){
22714 Roo.dd.ScrollManager.register(this.el);
22718 * @scope Roo.dd.DropTarget
22723 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22724 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22725 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22727 * IMPORTANT : it should set this.valid to true|false
22729 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22730 * @param {Event} e The event
22731 * @param {Object} data An object containing arbitrary data supplied by the drag source
22737 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22738 * This method will be called on every mouse movement while the drag source is over the drop target.
22739 * This default implementation simply returns the dropAllowed config value.
22741 * IMPORTANT : it should set this.valid to true|false
22743 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22744 * @param {Event} e The event
22745 * @param {Object} data An object containing arbitrary data supplied by the drag source
22751 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22752 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22753 * overClass (if any) from the drop element.
22756 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22757 * @param {Event} e The event
22758 * @param {Object} data An object containing arbitrary data supplied by the drag source
22764 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22765 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22766 * implementation that does something to process the drop event and returns true so that the drag source's
22767 * repair action does not run.
22769 * IMPORTANT : it should set this.success
22771 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22772 * @param {Event} e The event
22773 * @param {Object} data An object containing arbitrary data supplied by the drag source
22779 Roo.dd.DropTarget.superclass.constructor.call( this,
22781 this.ddGroup || this.group,
22784 listeners : listeners || {}
22792 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22794 * @cfg {String} overClass
22795 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22798 * @cfg {String} ddGroup
22799 * The drag drop group to handle drop events for
22803 * @cfg {String} dropAllowed
22804 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22806 dropAllowed : "x-dd-drop-ok",
22808 * @cfg {String} dropNotAllowed
22809 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22811 dropNotAllowed : "x-dd-drop-nodrop",
22813 * @cfg {boolean} success
22814 * set this after drop listener..
22818 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22819 * if the drop point is valid for over/enter..
22826 isNotifyTarget : true,
22831 notifyEnter : function(dd, e, data)
22834 this.fireEvent('enter', dd, e, data);
22835 if(this.overClass){
22836 this.el.addClass(this.overClass);
22838 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22839 this.valid ? this.dropAllowed : this.dropNotAllowed
22846 notifyOver : function(dd, e, data)
22849 this.fireEvent('over', dd, e, data);
22850 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22851 this.valid ? this.dropAllowed : this.dropNotAllowed
22858 notifyOut : function(dd, e, data)
22860 this.fireEvent('out', dd, e, data);
22861 if(this.overClass){
22862 this.el.removeClass(this.overClass);
22869 notifyDrop : function(dd, e, data)
22871 this.success = false;
22872 this.fireEvent('drop', dd, e, data);
22873 return this.success;
22877 * Ext JS Library 1.1.1
22878 * Copyright(c) 2006-2007, Ext JS, LLC.
22880 * Originally Released Under LGPL - original licence link has changed is not relivant.
22883 * <script type="text/javascript">
22888 * @class Roo.dd.DragZone
22889 * @extends Roo.dd.DragSource
22890 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22891 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22893 * @param {String/HTMLElement/Element} el The container element
22894 * @param {Object} config
22896 Roo.dd.DragZone = function(el, config){
22897 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22898 if(this.containerScroll){
22899 Roo.dd.ScrollManager.register(this.el);
22903 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22905 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22906 * for auto scrolling during drag operations.
22909 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22910 * method after a failed drop (defaults to "c3daf9" - light blue)
22914 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22915 * for a valid target to drag based on the mouse down. Override this method
22916 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22917 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22918 * @param {EventObject} e The mouse down event
22919 * @return {Object} The dragData
22921 getDragData : function(e){
22922 return Roo.dd.Registry.getHandleFromEvent(e);
22926 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22927 * this.dragData.ddel
22928 * @param {Number} x The x position of the click on the dragged object
22929 * @param {Number} y The y position of the click on the dragged object
22930 * @return {Boolean} true to continue the drag, false to cancel
22932 onInitDrag : function(x, y){
22933 this.proxy.update(this.dragData.ddel.cloneNode(true));
22934 this.onStartDrag(x, y);
22939 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22941 afterRepair : function(){
22943 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22945 this.dragging = false;
22949 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22950 * the XY of this.dragData.ddel
22951 * @param {EventObject} e The mouse up event
22952 * @return {Array} The xy location (e.g. [100, 200])
22954 getRepairXY : function(e){
22955 return Roo.Element.fly(this.dragData.ddel).getXY();
22959 * Ext JS Library 1.1.1
22960 * Copyright(c) 2006-2007, Ext JS, LLC.
22962 * Originally Released Under LGPL - original licence link has changed is not relivant.
22965 * <script type="text/javascript">
22968 * @class Roo.dd.DropZone
22969 * @extends Roo.dd.DropTarget
22970 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22971 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22973 * @param {String/HTMLElement/Element} el The container element
22974 * @param {Object} config
22976 Roo.dd.DropZone = function(el, config){
22977 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22980 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22982 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22983 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22984 * provide your own custom lookup.
22985 * @param {Event} e The event
22986 * @return {Object} data The custom data
22988 getTargetFromEvent : function(e){
22989 return Roo.dd.Registry.getTargetFromEvent(e);
22993 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22994 * that it has registered. This method has no default implementation and should be overridden to provide
22995 * node-specific processing if necessary.
22996 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22997 * {@link #getTargetFromEvent} for this node)
22998 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22999 * @param {Event} e The event
23000 * @param {Object} data An object containing arbitrary data supplied by the drag source
23002 onNodeEnter : function(n, dd, e, data){
23007 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23008 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
23009 * overridden to provide the proper feedback.
23010 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23011 * {@link #getTargetFromEvent} for this node)
23012 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23013 * @param {Event} e The event
23014 * @param {Object} data An object containing arbitrary data supplied by the drag source
23015 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23016 * underlying {@link Roo.dd.StatusProxy} can be updated
23018 onNodeOver : function(n, dd, e, data){
23019 return this.dropAllowed;
23023 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23024 * the drop node without dropping. This method has no default implementation and should be overridden to provide
23025 * node-specific processing if necessary.
23026 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23027 * {@link #getTargetFromEvent} for this node)
23028 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23029 * @param {Event} e The event
23030 * @param {Object} data An object containing arbitrary data supplied by the drag source
23032 onNodeOut : function(n, dd, e, data){
23037 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23038 * the drop node. The default implementation returns false, so it should be overridden to provide the
23039 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23040 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23041 * {@link #getTargetFromEvent} for this node)
23042 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23043 * @param {Event} e The event
23044 * @param {Object} data An object containing arbitrary data supplied by the drag source
23045 * @return {Boolean} True if the drop was valid, else false
23047 onNodeDrop : function(n, dd, e, data){
23052 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23053 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
23054 * it should be overridden to provide the proper feedback if necessary.
23055 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23056 * @param {Event} e The event
23057 * @param {Object} data An object containing arbitrary data supplied by the drag source
23058 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23059 * underlying {@link Roo.dd.StatusProxy} can be updated
23061 onContainerOver : function(dd, e, data){
23062 return this.dropNotAllowed;
23066 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23067 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
23068 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23069 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
23070 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23071 * @param {Event} e The event
23072 * @param {Object} data An object containing arbitrary data supplied by the drag source
23073 * @return {Boolean} True if the drop was valid, else false
23075 onContainerDrop : function(dd, e, data){
23080 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23081 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
23082 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23083 * you should override this method and provide a custom implementation.
23084 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23085 * @param {Event} e The event
23086 * @param {Object} data An object containing arbitrary data supplied by the drag source
23087 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23088 * underlying {@link Roo.dd.StatusProxy} can be updated
23090 notifyEnter : function(dd, e, data){
23091 return this.dropNotAllowed;
23095 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23096 * This method will be called on every mouse movement while the drag source is over the drop zone.
23097 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23098 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23099 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23100 * registered node, it will call {@link #onContainerOver}.
23101 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23102 * @param {Event} e The event
23103 * @param {Object} data An object containing arbitrary data supplied by the drag source
23104 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23105 * underlying {@link Roo.dd.StatusProxy} can be updated
23107 notifyOver : function(dd, e, data){
23108 var n = this.getTargetFromEvent(e);
23109 if(!n){ // not over valid drop target
23110 if(this.lastOverNode){
23111 this.onNodeOut(this.lastOverNode, dd, e, data);
23112 this.lastOverNode = null;
23114 return this.onContainerOver(dd, e, data);
23116 if(this.lastOverNode != n){
23117 if(this.lastOverNode){
23118 this.onNodeOut(this.lastOverNode, dd, e, data);
23120 this.onNodeEnter(n, dd, e, data);
23121 this.lastOverNode = n;
23123 return this.onNodeOver(n, dd, e, data);
23127 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23128 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23129 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23130 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23131 * @param {Event} e The event
23132 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23134 notifyOut : function(dd, e, data){
23135 if(this.lastOverNode){
23136 this.onNodeOut(this.lastOverNode, dd, e, data);
23137 this.lastOverNode = null;
23142 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23143 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23144 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23145 * otherwise it will call {@link #onContainerDrop}.
23146 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23147 * @param {Event} e The event
23148 * @param {Object} data An object containing arbitrary data supplied by the drag source
23149 * @return {Boolean} True if the drop was valid, else false
23151 notifyDrop : function(dd, e, data){
23152 if(this.lastOverNode){
23153 this.onNodeOut(this.lastOverNode, dd, e, data);
23154 this.lastOverNode = null;
23156 var n = this.getTargetFromEvent(e);
23158 this.onNodeDrop(n, dd, e, data) :
23159 this.onContainerDrop(dd, e, data);
23163 triggerCacheRefresh : function(){
23164 Roo.dd.DDM.refreshCache(this.groups);